### Build the Included Example with CMake Presets Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Configures and builds the example plugin using the provided CMake presets. The example is not built unless COMMONLIBF4RD_BUILD_EXAMPLE is enabled when included from another project. ```text cmake --preset vs2022-windows-vcpkg cmake --build --preset vs2022-release ``` -------------------------------- ### Clone the CommonLibF4RD Example Plugin Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Clones the complete standalone example plugin project with submodules. Use as a starting point for new plugins or as a migration reference. ```text git clone --recursive https://github.com/Zzyxz/CommonLibF4RD-ExamplePlugin.git ``` -------------------------------- ### Install header directories Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Installs the F4SE, RE, and REL header directories to the include directory. ```cmake install( DIRECTORY "include/F4SE" "include/RE" "include/REL" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) ``` -------------------------------- ### Generate and install package config file Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Configures cmake/config.cmake.in into CommonLibF4Config.cmake and installs it to the CMake package directory. ```cmake configure_file( "cmake/config.cmake.in" "${PROJECT_NAME}Config.cmake" @ONLY ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) ``` -------------------------------- ### Install and export targets Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Installs the library target and exports it with the CommonLibF4:: namespace to the CMake package directory. ```cmake install( TARGETS "${PROJECT_NAME}" EXPORT "${PROJECT_NAME}-targets" ) install( EXPORT "${PROJECT_NAME}-targets" NAMESPACE "${PROJECT_NAME}::" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) ``` -------------------------------- ### Example mapping file contents Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Example of the mapping file format: each line contains an ID and its resolved RVA in hexadecimal. ```text 343176 0x48A0 224532 0xA8A0 ``` -------------------------------- ### Set include directories and link libraries Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Specifies public include directories for build and install interfaces, and links the target against Boost headers, fmt, mmio, spdlog, Zydis, and Version.lib. ```cmake target_include_directories( "${PROJECT_NAME}" PUBLIC "$" "$" ) target_link_libraries( "${PROJECT_NAME}" PUBLIC Boost::headers fmt::fmt mmio::mmio spdlog::spdlog Zydis::Zydis Version.lib ) ``` -------------------------------- ### CMake project setup and in-source build check Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Sets the minimum CMake version to 3.21, defines the CommonLibF4 project with CXX language, and aborts with a fatal error if an in-source build is attempted. ```cmake cmake_minimum_required(VERSION 3.21) project( CommonLibF4 LANGUAGES CXX ) if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") message(FATAL_ERROR "in-source builds are not allowed") endif() ``` -------------------------------- ### CMake configuration for CommonLibF4RD Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CMakeLists.txt Sets minimum CMake version to 3.21, defines project CommonLibF4RD, and provides an option COMMONLIBF4RD_BUILD_EXAMPLE to build the example plugin (defaults to true when top-level). It also defines a function conditionally_add_subdirectory to avoid adding subdirectories that are already targets, and uses it to add CommonLibF4 and optionally ExampleProject. ```cmake cmake_minimum_required(VERSION 3.21) project(CommonLibF4RD) option(COMMONLIBF4RD_BUILD_EXAMPLE "Build the included example plugin" ${PROJECT_IS_TOP_LEVEL}) if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") message(FATAL_ERROR "in-source builds are not allowed") endif() function(conditionally_add_subdirectory SRC_DIR) if(NOT TARGET "${SRC_DIR}") if("${ARGC}" GREATER 1) add_subdirectory("${SRC_DIR}" "${ARGV1}") else() add_subdirectory("${SRC_DIR}") endif() endif() endfunction() conditionally_add_subdirectory(CommonLibF4) if(COMMONLIBF4RD_BUILD_EXAMPLE) conditionally_add_subdirectory(ExampleProject) endif() ``` -------------------------------- ### Initialize F4SE and let required relocations determine operation Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Recommended initialization pattern: call F4SE::Init, log the runtime version, and then initialize plugin features. Required relocations determine whether the plugin can operate. ```cpp F4SE::Init(a_f4se); logger::info("Loaded on runtime {}", a_f4se->RuntimeVersion().string()); return InitializePluginFeatures(); ``` -------------------------------- ### Create complete runtime mapping file Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Create an empty .mapping file next to the DLL to enable full mapping. The file is overwritten with a complete ID RVA mapping for the current runtime. If any entries cannot be resolved, a companion .fail file is created automatically. Full mapping may increase startup time and should not be enabled for normal gameplay. ```text RobCoPatcherRD.dll RobCoPatcherRD.mapping ``` -------------------------------- ### Include source list and set up source groups Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Includes the cmake/sourcelist.cmake file and organizes source files into source groups based on their directory tree. ```cmake include("cmake/sourcelist.cmake") source_group( TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES} ) ``` -------------------------------- ### CMakeLists.txt: Full project configuration Source: https://github.com/zzyxz/commonlibf4rd/blob/main/ExampleProject/CMakeLists.txt Complete CMake configuration for building a Fallout 4 plugin DLL with CommonLibF4. Sets minimum CMake version 3.20, defines COPY_BUILD option, reads Fallout4Path and VCPKG_ROOT from environment, configures vcpkg toolchain, sets MSVC runtime to MultiThreaded DLL, creates project ExampleProject version 1.0.0, configures version headers, prevents in-source builds, sets compiler options (including /MP, /W4, /WX), links fmt and spdlog, and optionally copies output to Fallout4Path/Data/F4SE/Plugins/. ```CMake cmake_minimum_required(VERSION 3.20) # ---- Options ---- option(COPY_BUILD "Copy the build output to the Fallout 4 directory." OFF) # ---- Cache build vars ---- macro(set_from_environment VARIABLE) if (NOT DEFINED ${VARIABLE} AND DEFINED ENV{${VARIABLE}}) set(${VARIABLE} $ENV{${VARIABLE}}) endif () endmacro() set_from_environment(Fallout4Path) set_from_environment(VCPKG_ROOT) if (DEFINED VCPKG_ROOT) set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") set(VCPKG_TARGET_TRIPLET "x64-windows-static-md" CACHE STRING "") else () message( WARNING "Variable VCPKG_ROOT is not set. Continuing without vcpkg." ) endif () set(Boost_USE_STATIC_RUNTIME OFF CACHE BOOL "") set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL" CACHE STRING "") # ---- Project ---- project( ExampleProject VERSION 1.0.0 LANGUAGES CXX ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/Version.h @ONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY ) # ---- Include guards ---- if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there." ) endif () # ---- Globals ---- if (MSVC) if (NOT ${CMAKE_GENERATOR} STREQUAL "Ninja") add_compile_options( /MP # Build with Multiple Processes ) endif () endif () set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_DEBUG OFF) set(Boost_USE_STATIC_LIBS ON) # ---- Dependencies ---- if (NOT TARGET CommonLibF4) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../CommonLibF4" CommonLibF4) endif () find_package(fmt REQUIRED CONFIG) find_package(spdlog REQUIRED CONFIG) # ---- Add source files ---- include(cmake/sourcelist.cmake) source_group( TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES} ) source_group( TREE ${CMAKE_CURRENT_BINARY_DIR} FILES ${CMAKE_CURRENT_BINARY_DIR}/include/Version.h ) # ---- Create DLL ---- add_library( ${PROJECT_NAME} SHARED ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/version.rc .clang-format ) target_compile_definitions( ${PROJECT_NAME} PRIVATE _UNICODE ) target_compile_features( ${PROJECT_NAME} PRIVATE cxx_std_20 ) target_include_directories( ${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src ) target_link_libraries( ${PROJECT_NAME} PRIVATE CommonLibF4::CommonLibF4 fmt::fmt spdlog::spdlog ) target_precompile_headers( ${PROJECT_NAME} PRIVATE src/PCH.h ) if (MSVC) target_compile_options( ${PROJECT_NAME} PRIVATE /sdl # Enable Additional Security Checks /utf-8 # Set Source and Executable character sets to UTF-8 /Zi # Debug Information Format /permissive- # Standards conformance /Zc:preprocessor # Enable preprocessor conformance mode /W4 # Warning level /WX # Warning level (warnings are errors) "$<$:>" "$<$:/Zc:inline;/JMC->" ) target_link_options( ${PROJECT_NAME} PRIVATE /WX # Treat Linker Warnings as Errors "$<$:/INCREMENTAL;/OPT:NOREF;/OPT:NOICF>" "$<$:/INCREMENTAL:NO;/OPT:REF;/OPT:ICF;/DEBUG:FULL>" ) endif () # ---- File copying ---- if (COPY_BUILD) if (DEFINED Fallout4Path) add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${Fallout4Path}/Data/F4SE/Plugins/ COMMAND ${CMAKE_COMMAND} -E copy $ ${Fallout4Path}/Data/F4SE/Plugins/ ) else () message( WARNING "Variable Fallout4Path is not defined. Skipping post-build copy command." ) endif () endif () ``` -------------------------------- ### Create per-plugin trace file Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Create an empty .trace file next to the plugin DLL to enable tracing. The file is overwritten and populated with the IDs requested by that plugin, including resolved RVAs and additional details for VariantOffset or AUTO_CALLSITE relocations. Tracing is opt-in; delete or rename the file to disable it. ```text RobCoPatcherRD.dll RobCoPatcherRD.trace ``` -------------------------------- ### Complete runtime mapping file Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Create an empty .mapping file next to the DLL to enable complete runtime mapping. The file is overwritten with a complete ID RVA mapping for the current runtime. ```APIDOC ## Complete runtime mapping file ### Description Create an empty .mapping file next to the DLL to enable complete runtime mapping. The file is overwritten with a complete ID RVA mapping for the current runtime. ### Usage Create an empty file named `.mapping` next to the DLL before starting the game. ### Output A file containing lines of `ID RVA` pairs, for example: ``` 343176 0x48A0 224532 0xA8A0 ``` ### Failure file If any entries cannot be resolved, a companion file `.mapping.fail` is created automatically. The failure file contains the ID and reason. `runtime_unavailable` means the symbol is known but does not exist in the active runtime. ### Performance Full mapping is a diagnostic operation and may noticeably increase startup time. It should not be enabled for normal gameplay or release packages. ``` -------------------------------- ### Find required dependencies Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Locates the required packages: Boost, fmt, mmio, spdlog, and Zydis, all using CONFIG mode. ```cmake find_package(Boost CONFIG REQUIRED) find_package(fmt REQUIRED CONFIG) find_package(mmio REQUIRED CONFIG) find_package(spdlog REQUIRED CONFIG) find_package(Zydis REQUIRED CONFIG) ``` -------------------------------- ### Per-plugin trace file Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Create an empty .trace file next to the plugin DLL to enable per-plugin tracing. The file is overwritten with the IDs requested by that plugin and their resolved RVAs. ```APIDOC ## Per-plugin trace file ### Description Create an empty .trace file next to the plugin DLL to enable per-plugin tracing. The file is overwritten with the IDs requested by that plugin and their resolved RVAs. ### Usage Create an empty file named `.trace` next to the plugin DLL before starting the game. ### Output Entries contain the resolved RVA. Relocations using `VariantOffset` or `AUTO_CALLSITE` additionally include the selected offset, final RVA, runtime slot, and whether the offset was fixed or automatic. ### Disabling Delete or rename the `.trace` file to disable tracing. ``` -------------------------------- ### Create failure file for unresolved mappings Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md If any entries cannot be resolved, a companion file is created automatically. The failure file contains the ID and reason. The reason 'runtime_unavailable' means the symbol is known but does not exist in the active runtime. ```text RobCoPatcherRD.mapping.fail ``` -------------------------------- ### Runtime Database Path Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Specifies the required location for the CommonLibF4RD Runtime Database. The file is distributed separately and plugins do not select or rename it. ```text Data/F4SE/Plugins/f4rd-runtime.bin ``` -------------------------------- ### Set Plugin Compatibility Metadata Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Sets F4SE address and structure independence metadata instead of an exact executable-version whitelist. Required IDs, callsites, and ABI assumptions must still fail safely when they cannot be validated. ```cpp data.addressIndependence = F4SE::PluginVersionData::kAddressIndependence_Signatures; data.structureIndependence = F4SE::PluginVersionData::kStructureIndependence_1_10_980Layout | F4SE::PluginVersionData::kStructureIndependence_1_11_137Layout; ``` -------------------------------- ### vcpkg Manifest Dependencies for CommonLibF4RD Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Lists the required vcpkg packages for the plugin. The manifest must provide these packages. ```json { "dependencies": [ "boost-stl-interfaces", "fmt", "rsm-mmio", "spdlog", "zydis" ] } ``` -------------------------------- ### Avoid hard-blocking executable versions Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Shows an anti-pattern: rejecting the game if the runtime version is not in a hard-coded list. This prevents normal updates from reaching the Runtime Database and attempting resolution. ```cpp const auto version = a_f4se->RuntimeVersion(); if (version != F4SE::RUNTIME_1_11_221 && version != F4SE::RUNTIME_1_11_240) { return false; } ``` -------------------------------- ### Add static library target and alias Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Creates the static library target CommonLibF4 from the SOURCES variable, including .clang-format and CommonLibF4.natvis files, and defines an alias target CommonLibF4::CommonLibF4. ```cmake include(GNUInstallDirs) add_library( "${PROJECT_NAME}" STATIC ${SOURCES} "../.clang-format" "CommonLibF4.natvis" ) add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS "${PROJECT_NAME}") ``` -------------------------------- ### Enable precompiled headers Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Configures a private precompiled header for the target using include/F4SE/Impl/PCH.h. ```cmake target_precompile_headers( "${PROJECT_NAME}" PRIVATE "include/F4SE/Impl/PCH.h" ) ``` -------------------------------- ### Link CommonLibF4::CommonLibF4 CMake target Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/README.md Add this line to your CMakeLists.txt to link the CommonLibF4 library to your project. Requires the listed vcpkg packages: boost-stl-interfaces, fmt, rsm-mmio, spdlog, and zydis. ```cmake target_link_libraries(${PROJECT_NAME} PRIVATE CommonLibF4::CommonLibF4) ``` -------------------------------- ### REL::AUTO_CALLSITE for all runtime families Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Enables automatic resolution for every runtime family by using only REL::AUTO_CALLSITE(target) in the VariantOffset. ```cpp REL::Relocation hookSite{ owner, REL::VariantOffset{ REL::AUTO_CALLSITE(target) } }; ``` -------------------------------- ### Add CommonLibF4RD as a Git Submodule Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Adds the CommonLibF4RD repository as a source dependency in the plugin's Git repository. ```text git submodule add https://github.com/Zzyxz/CommonLibF4RD.git external/CommonLibF4RD ``` -------------------------------- ### Resolve all callsites with REL::resolve_callsites Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Use this to inspect or handle every matching callsite. It returns a result with a status and a list of RVAs. If resolution fails, the status text can be logged. Hooking every callsite is not automatically safe; each location must have the expected calling convention, register state, and logical purpose. ```cpp const auto calls = REL::resolve_callsites(owner, target); if (!calls) { logger::error("Callsites could not be resolved: {}", REL::id_resolve_status_text(calls.status)); return; } for (const auto rva : calls.rvas) { REL::Relocation callsite{ REL::Offset(rva) }; // Validate the call context before installing a hook. } ``` -------------------------------- ### MSVC-specific compile options and warning handling Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Configures MSVC compiler options: enables standards conformance, disables specific warnings publicly, and promotes warning 4715 to an error privately while disabling additional warnings. ```cmake if(MSVC) target_compile_options( "${PROJECT_NAME}" PUBLIC "/permissive-" # Standards conformance # disable warnings "/wd4200" # nonstandard extension used : zero-sized array in struct/union "/wd4201" # nonstandard extension used : nameless struct/union "/wd4324" # 'struct_name' : structure was padded due to __declspec(align()) PRIVATE # warnings -> errors "/we4715" # 'function' : not all control paths return a value # disable warnings "/wd4061" # enumerator 'identifier' in switch of enum 'enumeration' is not explicitly handled by a case label "/wd4263" # 'function' : member function does not override any base class virtual member function "/wd4264" # 'virtual_function' : no override available for virtual member function from base 'class'; function is hidden "/wd4266" # 'function' : no override available for virtual member function from base 'type'; function is hidden "/wd4371" # 'classname': layout of class may have changed from a previous version of the compiler due to better packing of member 'member' "/wd4514" # 'function' : unreferenced inline function has been removed "/wd4582" # 'type': constructor is not implicitly called "/wd4583" # 'type': destructor is not implicitly called "/wd4623" # 'derived class' : default constructor was implicitly defined as deleted because a base class default constructor is inaccessible or deleted "/wd4625" # 'derived class' : copy constructor was implicitly defined as deleted because a base class copy constructor is inaccessible or deleted "/wd4626" # 'derived class' : assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted "/wd4686" # 'user-defined type' : possible change in behavior, change in UDT return calling convention "/wd4820" # 'bytes' bytes padding added after construct 'member_name' "/wd5027" # 'type': move assignment operator was implicitly defined as deleted "/wd5045" # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified "/wd5053" # support for 'explicit()' in C++17 and earlier is a vendor extension "/wd5204" # 'type-name': class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly "/wd5220" # 'member': a non-static data member with a volatile qualified type no longer implies that compiler generated copy / move constructors and copy / move assignment operators are not trivial ) endif() ``` -------------------------------- ### CMake Integration for CommonLibF4RD Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Adds the CommonLibF4RD subdirectory and links its public target. Required to build a plugin against the library. ```cmake add_subdirectory( "${CMAKE_CURRENT_SOURCE_DIR}/external/CommonLibF4RD/CommonLibF4" CommonLibF4 ) target_link_libraries( ${PROJECT_NAME} PRIVATE CommonLibF4::CommonLibF4 ) ``` -------------------------------- ### Include the CommonLibF4RD Umbrella Header Source: https://github.com/zzyxz/commonlibf4rd/blob/main/README.md Includes the umbrella header from the plugin's precompiled header. Individual RE and REL headers assume this header has supplied shared platform and standard-library declarations. ```cpp #include ``` -------------------------------- ### REL::VariantOffset constructor Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Constructs a REL::VariantOffset with one, two, or three runtime-specific offsets. The argument order is always (OG, NG, AE). Selects the correct relative offset for the active runtime family. ```APIDOC ## REL::VariantOffset constructor ### Description Constructs a REL::VariantOffset with one, two, or three runtime-specific offsets. The argument order is always (OG, NG, AE). Selects the correct relative offset for the active runtime family. ### Method Constructor ### Endpoint REL::VariantOffset(uint32_t og, uint32_t ng, uint32_t ae) ### Parameters #### Constructor Parameters - **og** (uint32_t) - Optional - OG runtime offset. If omitted, the AE offset is used for OG when a bridge is available. - **ng** (uint32_t) - Optional - NG runtime offset. If omitted, the AE offset is used for NG when a bridge is available. - **ae** (uint32_t) - Required - AE runtime offset. Always required. ### Usage Examples ```cpp // The same offset for OG, NG, and AE. REL::VariantOffset(0x8F7) // OG, modern. The second value is used by both NG and AE. REL::VariantOffset(0x921, 0x8F7) // OG, NG, AE. REL::VariantOffset(0x921, 0x930, 0x8F7) ``` ### Behavior - Selects a runtime family, not an individual executable patch. For example, 1.11.221 and 1.11.240 both use the AE value. - Can be passed directly to a relocation. ### Usage with Relocation ```cpp REL::Relocation hookSite{ REL::ID(1546751, 2229323), REL::VariantOffset(0x921, 0x8F7) }; ``` ### Notes - If an interior hook position may move between updates within the same family, prefer automatic callsite resolution. ``` -------------------------------- ### Set compile definitions and C++ standard Source: https://github.com/zzyxz/commonlibf4rd/blob/main/CommonLibF4/CMakeLists.txt Defines public compile definitions for Windows 7 compatibility and disables Boost concepts, and requires C++20 as a public compile feature. ```cmake target_compile_definitions( "${PROJECT_NAME}" PUBLIC BOOST_STL_INTERFACES_DISABLE_CONCEPTS WINVER=0x0601 # windows 7, minimum supported version by fallout 4 _WIN32_WINNT=0x0601 ) target_compile_features( "${PROJECT_NAME}" PUBLIC cxx_std_20 ) ``` -------------------------------- ### REL::VariantOffset with one, two, or three offsets Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Shows the three supported forms of REL::VariantOffset: the same offset for all runtimes, two offsets (OG, modern) where the second is used by both NG and AE, and three offsets (OG, NG, AE). ```cpp // The same offset for OG, NG, and AE. REL::VariantOffset(0x8F7) // OG, modern. The second value is used by both NG and AE. REL::VariantOffset(0x921, 0x8F7) // OG, NG, AE. REL::VariantOffset(0x921, 0x930, 0x8F7) ``` -------------------------------- ### REL::AUTO_CALLSITE_FIRST(target) Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Selects the first callsite of a target. This is a macro that can be used in place of a unique callsite selector. ```APIDOC ## REL::AUTO_CALLSITE_FIRST(target) ### Description Selects the first callsite of a target. This is a macro that can be used in place of a unique callsite selector. ### Method Macro ### Parameters - **target** - The target function or address to find callsites for. ### Example ```cpp REL::AUTO_CALLSITE_FIRST(target) ``` ``` -------------------------------- ### REL::ID constructor Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Constructs a REL::ID with one, two, or three runtime-specific IDs. The argument order is always (OG, NG, AE). Supports lazy resolution with caching and reports specific failures if an ID cannot be resolved. ```APIDOC ## REL::ID constructor ### Description Constructs a REL::ID with one, two, or three runtime-specific IDs. The argument order is always (OG, NG, AE). Supports lazy resolution with caching and reports specific failures if an ID cannot be resolved. ### Method Constructor ### Endpoint REL::ID(uint32_t og, uint32_t ng, uint32_t ae) ### Parameters #### Constructor Parameters - **og** (uint32_t) - Optional - OG runtime ID. If omitted, the AE ID is used for OG when a bridge is available. - **ng** (uint32_t) - Optional - NG runtime ID. If omitted, the AE ID is used for NG when a bridge is available. - **ae** (uint32_t) - Required - AE runtime ID. Always required. ### Usage Examples ```cpp // One portable AE ID. NG and OG may resolve the same logical ID when supported. REL::ID(2229323) // OG, AE. NG uses the AE ID. REL::ID(1546751, 2229323) // OG, NG, AE. REL::ID(1546751, 2229323, 2229323) ``` ### Behavior - IDs are resolved lazily only when requested by the plugin. - Successful results are cached; repeated use of the same ID does not repeat full resolution. - If an ID cannot be resolved, a specific failure is reported instead of returning an unsafe address. - If an implicit OG or NG bridge is unavailable, resolution fails with `og_bridge_failed` or `ng_bridge_failed`. ### Error Handling - `og_bridge_failed` - Thrown when an implicit OG bridge is unavailable and no explicit OG ID is provided. - `ng_bridge_failed` - Thrown when an implicit NG bridge is unavailable and no explicit NG ID is provided. ``` -------------------------------- ### Select specific callsites with AUTO_CALLSITE macros Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Use these macros to select a specific occurrence of a target call. The NTH variant is zero-based, so 2 selects the third match. These selectors are less robust than unique matching because updates may reorder or insert calls. ```cpp REL::AUTO_CALLSITE_FIRST(target) REL::AUTO_CALLSITE_LAST(target) REL::AUTO_CALLSITE_NTH(target, 2) // zero-based: selects the third match ``` -------------------------------- ### REL::Relocation with REL::ID and REL::VariantOffset Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Passes a REL::VariantOffset directly to a relocation to select the correct relative offset for the active runtime family. VariantOffset selects a runtime family, not an individual executable patch. ```cpp REL::Relocation hookSite{ REL::ID(1546751, 2229323), REL::VariantOffset(0x921, 0x8F7) }; ``` -------------------------------- ### REL::AUTO_CALLSITE with fixed offsets for OG and AE Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Default form of REL::AUTO_CALLSITE requiring exactly one matching callsite. Uses fixed offsets for OG and AE, and automatic discovery for NG. ```cpp constexpr REL::ID owner{ 1546751, // OG 2229323 // AE; also used by NG }; constexpr REL::ID target{ 881215, // OG 2231148 // AE; also used by NG }; REL::Relocation hookSite{ owner, REL::VariantOffset{ 0x921, // OG: known fixed offset REL::AUTO_CALLSITE(target), // NG: discover it at runtime 0x8F7 // AE: known fixed offset } }; ``` -------------------------------- ### REL::Relocation with REL::ID Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md The familiar form of creating a relocation using a single REL::ID. Only IDs requested by the plugin are resolved during normal operation, and successful results are cached. ```cpp REL::Relocation function{ REL::ID(2229323) }; ``` -------------------------------- ### REL::ID with one, two, or three IDs Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Shows the three supported forms of REL::ID: one portable AE ID, two IDs (OG, AE) where NG uses the AE ID, and three IDs (OG, NG, AE). The argument order is always REL::ID(OG, NG, AE). ```cpp // One portable AE ID. NG and OG may resolve the same logical ID when supported. REL::ID(2229323) // OG, AE. NG uses the AE ID. REL::ID(1546751, 2229323) // OG, NG, AE. REL::ID(1546751, 2229323, 2229323) ``` -------------------------------- ### REL::AUTO_CALLSITE_NTH(target, n) Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Selects the nth callsite of a target, zero-based. This is a macro that can be used in place of a unique callsite selector. ```APIDOC ## REL::AUTO_CALLSITE_NTH(target, n) ### Description Selects the nth callsite of a target, zero-based. This is a macro that can be used in place of a unique callsite selector. ### Method Macro ### Parameters - **target** - The target function or address to find callsites for. - **n** (integer) - Zero-based index of the callsite to select. ### Example ```cpp REL::AUTO_CALLSITE_NTH(target, 2) // selects the third match ``` ``` -------------------------------- ### REL::AUTO_CALLSITE(target) Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Creates an automatic callsite offset that resolves the offset by finding the matching call inside the owner function. The default form requires exactly one matching callsite and uses a direct call branch type. ```APIDOC ## REL::AUTO_CALLSITE(target) ### Description Identifies a callsite by its logical relationship: resolve the owner function, resolve the function being called, find the matching call inside the owner function, and use the discovered offset for the running executable. The default form requires exactly one matching callsite. ### Usage Used as a variant offset in a `REL::Relocation` to automatically resolve the hook position at runtime. ### Parameters - **target** (REL::ID) - Required - The ID of the function being called. ### Branch Type Default is a direct call. Direct jumps and either form can be requested explicitly: - `REL::AUTO_CALLSITE(target, REL::AutoCallsiteBranch::kJump)` - `REL::AUTO_CALLSITE(target, REL::AutoCallsiteBranch::kCallOrJump)` ### Example ```cpp constexpr REL::ID owner{ 1546751, // OG 2229323 // AE; also used by NG }; constexpr REL::ID target{ 881215, // OG 2231148 // AE; also used by NG }; REL::Relocation hookSite{ owner, REL::VariantOffset{ 0x921, // OG: known fixed offset REL::AUTO_CALLSITE(target), // NG: discover it at runtime 0x8F7 // AE: known fixed offset } }; ``` Automatic resolution can also be enabled for every runtime family: ```cpp REL::Relocation hookSite{ owner, REL::VariantOffset{ REL::AUTO_CALLSITE(target) } }; ``` ### Errors Fails with `callsite_not_found` or `callsite_ambiguous` if the relationship is no longer safe to identify. ``` -------------------------------- ### REL::ID argument order Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md The argument order for REL::ID is always OG, NG, AE. Use the shortest form that is known to be correct. ```text REL::ID(OG, NG, AE) ``` -------------------------------- ### REL::AUTO_CALLSITE branch types Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Explicitly request a direct jump or either call or jump branch type using REL::AutoCallsiteBranch. ```cpp REL::AUTO_CALLSITE(target, REL::AutoCallsiteBranch::kJump) REL::AUTO_CALLSITE(target, REL::AutoCallsiteBranch::kCallOrJump) ``` -------------------------------- ### REL::AUTO_OFFSET Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md An automatic-offset marker. A relocation using it without an AUTO_CALLSITE target cannot determine which instruction is intended and therefore fails deliberately. Use REL::AUTO_CALLSITE(target) for an automatically resolved hook position. ```APIDOC ## REL::AUTO_OFFSET ### Description An automatic-offset marker. A relocation using it without an `AUTO_CALLSITE` target cannot determine which instruction is intended and therefore fails deliberately. Use `REL::AUTO_CALLSITE(target)` for an automatically resolved hook position. ### Usage Not intended for direct use as a hook position without an `AUTO_CALLSITE` target. ``` -------------------------------- ### REL::resolve_callsites(owner, target) Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Resolves all callsites of a target within an owner module. Returns a result containing the RVAs of all matching callsites. ```APIDOC ## REL::resolve_callsites(owner, target) ### Description Resolves all callsites of a target within an owner module. Returns a result containing the RVAs of all matching callsites. ### Method Function ### Parameters - **owner** - The module or address range to search for callsites. - **target** - The target function or address to find callsites for. ### Return Value - **calls** - A result object containing: - **status** - The resolution status. - **rvas** - A list of RVAs (relative virtual addresses) of the matching callsites. ### Example ```cpp const auto calls = REL::resolve_callsites(owner, target); if (!calls) { logger::error("Callsites could not be resolved: {}", REL::id_resolve_status_text(calls.status)); return; } for (const auto rva : calls.rvas) { REL::Relocation callsite{ REL::Offset(rva) }; // Validate the call context before installing a hook. } ``` ``` -------------------------------- ### REL::AUTO_CALLSITE_LAST(target) Source: https://github.com/zzyxz/commonlibf4rd/blob/main/docs/FEATURES.md Selects the last callsite of a target. This is a macro that can be used in place of a unique callsite selector. ```APIDOC ## REL::AUTO_CALLSITE_LAST(target) ### Description Selects the last callsite of a target. This is a macro that can be used in place of a unique callsite selector. ### Method Macro ### Parameters - **target** - The target function or address to find callsites for. ### Example ```cpp REL::AUTO_CALLSITE_LAST(target) ``` ```