From 6f5df531a7be5189d0f84074dfa33a4285ddf7fa Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Thu, 8 Oct 2026 20:24:57 +0800 Subject: [PATCH 1/2] feat(build): add shared clang-format targets and CI Co-Authored-By: Codex --- .clang-format-ignore | 5 +++++ .github/workflows/clang-format.yml | 31 ++++++++++++++++++++++++++++ .gitignore | 3 +++ CMakeLists.txt | 9 ++++++++ README.md | 33 ++++++++++++++++++++++++++++++ README.zh-CN.md | 30 +++++++++++++++++++++++++++ cmake/FormatValidation.cmake | 26 +++++++++++++++++++++++ 7 files changed, 137 insertions(+) create mode 100644 .clang-format-ignore create mode 100644 .github/workflows/clang-format.yml create mode 100644 cmake/FormatValidation.cmake diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 0000000..d2ff733 --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1,5 @@ +# Repository-relative exclusions for shared FormatValidation. +# Only src/, include/, and tests/ are selected; dependencies and artifacts are excluded. +**/thirdparty/** +**/build/** +**/install/** diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 0000000..e7736b0 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,31 @@ +name: clang-format + +on: + push: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: clang-format-${{ github.ref }} + cancel-in-progress: true + +jobs: + clang-format: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install pinned formatter + run: python -m pip install clang-format==23.1.3 + - name: Configure formatting targets + run: cmake -S . -B build/format -DFORMAT_VALIDATION_ONLY=ON + - name: Check all owned C/C++ sources + run: cmake --build build/format --target format-check diff --git a/.gitignore b/.gitignore index 81c7fe9..376022b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ /thirdparty/cache/ *.user __pycache__/ + +# Generated from the shared FormatValidation source during CMake configuration. +/.clang-format diff --git a/CMakeLists.txt b/CMakeLists.txt index 611f062..b1a7e13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,10 @@ cmake_minimum_required(VERSION 3.21) +option(FORMAT_VALIDATION_ONLY "Configure only clang-format targets without native dependencies" OFF) +if(FORMAT_VALIDATION_ONLY) + project(FormatValidation LANGUAGES NONE) + include(cmake/FormatValidation.cmake) + return() +endif() cmake_policy(SET CMP0091 NEW) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") project(PrecacheManager LANGUAGES CXX) @@ -94,3 +100,6 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) metahooksv_add_launch_game() endif() endif() + +# Shared formatting targets are explicit; ordinary native builds do not run them. +include(cmake/FormatValidation.cmake) diff --git a/README.md b/README.md index c097691..f52ca3b 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,36 @@ scripts\build-PrecacheManager-x86-Release.bat -DMETAHOOK_SOURCE_PATH=D:\MetaHook The path is the repository root that provides `include/metahook.h`, `include/HLSDK` and `include/Interface`. Pass `-DPRECACHEMANAGER_SYNC_GAMEDATA=OFF` to build without downloading gamedata. + +## C/C++ formatting + +Formatting uses [MetaHookSv/FormatValidation](https://github.com/MetaHookSv/FormatValidation) +and clang-format **23.1.3**, with the DiligentCore style (4 spaces, preserved include +order). Install the formatter for the Python interpreter used by CMake: + +```sh +python -m pip install clang-format==23.1.3 +cmake -S . -B build/format "-DFORMAT_VALIDATION_ONLY=ON" +cmake --build build/format --target format-check +cmake --build build/format --target format +``` + +The format-only configuration needs CMake 3.21+, Git, Python 3.9+ (CI uses 3.12), +and a build generator; `-G Ninja` works without Visual Studio. It prepares no native +SDK or game dependencies. Formatting targets are explicit and are not part of a +normal DLL build. With a Visual Studio generator, add `--config Debug` or +`--config Release` when building a formatting target. + +The aggregate provides `FORMAT_VALIDATION_SOURCE_PATH=thirdparty/FormatValidation`. +Standalone components accept that CMake variable or its environment counterpart; +if empty, FetchContent downloads the fixed tooling commit. Quote relative paths, +for example `"-DFORMAT_VALIDATION_SOURCE_PATH=../../thirdparty/FormatValidation"`. +Configuration generates the ignored root `.clang-format` for editors; change the +shared style rather than that generated copy. An optional +`FORMAT_VALIDATION_CLANG_FORMAT_EXECUTABLE` selects an explicit formatter, whose +version must still match the pin. + +Checks cover owned C/C++ files in `src/`, `include/`, and `tests/`, including +non-ignored new files. Repository-relative exclusions live in `.clang-format-ignore`. +Third-party sources and build artifacts are excluded. The `clang-format` workflow +checks the full scope on pushes, pull requests, and manual runs. diff --git a/README.zh-CN.md b/README.zh-CN.md index 2ebe1f2..71e6cdf 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -61,3 +61,33 @@ scripts\build-PrecacheManager-x86-Release.bat -DMETAHOOK_SOURCE_PATH=D:\MetaHook 该路径是提供 `include/metahook.h`、`include/HLSDK` 和 `include/Interface` 的仓库根目录。 传入 `-DPRECACHEMANAGER_SYNC_GAMEDATA=OFF` 可在构建期间跳过 gamedata 下载。 + +## C/C++ 格式化 + +使用 [MetaHookSv/FormatValidation](https://github.com/MetaHookSv/FormatValidation) +共享工具及固定版本 **clang-format 23.1.3**,采用 DiligentCore 风格(4 空格,保留 +include 顺序)。为 CMake 使用的 Python 解释器安装格式工具: + +```sh +python -m pip install clang-format==23.1.3 +cmake -S . -B build/format "-DFORMAT_VALIDATION_ONLY=ON" +cmake --build build/format --target format-check +cmake --build build/format --target format +``` + +格式专用配置需要 CMake 3.21+、Git、Python 3.9+(CI 使用 3.12)及构建生成器; +使用 `-G Ninja` 可无需 Visual Studio。它不准备原生 SDK 或游戏依赖。 +格式目标需显式执行,不加入普通 DLL 构建。使用 Visual Studio 生成器时,执行目标 +需追加 `--config Debug` 或 `--config Release`。 + +聚合仓库注入 `FORMAT_VALIDATION_SOURCE_PATH=thirdparty/FormatValidation`。 +独立组件支持该 CMake 参数及同名环境变量;为空时通过 FetchContent 获取固定工具 +提交。相对路径应加引号,例如 +`"-DFORMAT_VALIDATION_SOURCE_PATH=../../thirdparty/FormatValidation"`。 +配置时在仓库根目录生成被 gitignore 的 `.clang-format` 供编辑器使用;格式规则应 +在共享仓库修改,不修改生成副本。可通过 `FORMAT_VALIDATION_CLANG_FORMAT_EXECUTABLE` +指定工具路径,但版本仍须与固定版本一致。 + +检查覆盖 `src/`、`include/`、`tests/` 中维护的 C/C++ 文件,包括未被 Git 忽略的新文件。 +相对仓库根目录的排除规则位于 `.clang-format-ignore`;第三方源和构建产物不纳入检查。 +`clang-format` workflow 在 push、pull request 和手动运行时执行全量检查。 diff --git a/cmake/FormatValidation.cmake b/cmake/FormatValidation.cmake new file mode 100644 index 0000000..ed6d48c --- /dev/null +++ b/cmake/FormatValidation.cmake @@ -0,0 +1,26 @@ +# Shared tool implementation; only this dependency bootstrap belongs to the consumer. +if(NOT DEFINED FORMAT_VALIDATION_SOURCE_PATH) + set(FORMAT_VALIDATION_SOURCE_PATH "$ENV{FORMAT_VALIDATION_SOURCE_PATH}" CACHE PATH + "FormatValidation source tree; empty fetches the pinned tooling") +endif() +if(FORMAT_VALIDATION_SOURCE_PATH) + get_filename_component(_format_validation_source "${FORMAT_VALIDATION_SOURCE_PATH}" + ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}/..") +else() + include(FetchContent) + FetchContent_Declare(precachemanager_format_validation + GIT_REPOSITORY https://github.com/MetaHookSv/FormatValidation.git + GIT_TAG 13c9fabe058e1f887ad1b03bb6884de911192c6a # v1.0.0; retained immutable tooling commit + GIT_SUBMODULES "" + # Populate the tooling without configuring its own test project. + SOURCE_SUBDIR cmake) + FetchContent_MakeAvailable(precachemanager_format_validation) + set(_format_validation_source "${precachemanager_format_validation_SOURCE_DIR}") +endif() +foreach(_format_validation_file .clang-format clang-format-validate.py cmake/FormatValidation.cmake) + if(NOT EXISTS "${_format_validation_source}/${_format_validation_file}") + message(FATAL_ERROR "FORMAT_VALIDATION_SOURCE_PATH is missing ${_format_validation_file}: ${_format_validation_source}") + endif() +endforeach() +include("${_format_validation_source}/cmake/FormatValidation.cmake") +format_validation_add_component(PrecacheManager "${CMAKE_CURRENT_SOURCE_DIR}") From 3de80afb0815bd1aeaea5b9c60c51e9a352da397 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Thu, 8 Oct 2026 20:24:57 +0800 Subject: [PATCH 2/2] style: apply shared clang-format style Format maintained C/C++ sources with clang-format 23.1.3 while retaining include order. Co-Authored-By: Codex --- src/exportfuncs.cpp | 144 ++++++++++++++++++++++---------------------- src/plugins.cpp | 83 +++++++++++++------------ src/plugins.h | 55 ++++++++++------- src/privatehook.cpp | 48 +++++++-------- src/privatehook.h | 46 +++++++------- 5 files changed, 193 insertions(+), 183 deletions(-) diff --git a/src/exportfuncs.cpp b/src/exportfuncs.cpp index c1829c9..1bc7f47 100644 --- a/src/exportfuncs.cpp +++ b/src/exportfuncs.cpp @@ -11,85 +11,85 @@ #include #include -cl_enginefunc_t gEngfuncs; -engine_studio_api_t IEngineStudio; -r_studio_interface_t **gpStudioInterface; +cl_enginefunc_t gEngfuncs; +engine_studio_api_t IEngineStudio; +r_studio_interface_t** gpStudioInterface; -resource_t *cl_resourcesonhand = NULL; +resource_t* cl_resourcesonhand = NULL; void FS_Dump_Precaches(void) { - const char *mapname = gEngfuncs.pfnGetLevelName(); - - if (!mapname || !mapname[0]) - { - gEngfuncs.Con_Printf("FS_Dump_Precaches: Cannot dump precache resource list because you are not in an active map!\n"); - return; - } - - std::string filename = mapname; - - filename = filename.substr(0, filename.length() - 4); - - filename = filename + ".dump.res"; - - auto FileHandle = FILESYSTEM_ANY_OPEN(filename.c_str(), "wt"); - - if (!FileHandle) - { - gEngfuncs.Con_Printf("FS_Dump_Precaches: Could not open \"%s\" for writing!\n", filename.c_str()); - return; - } - - resource_t *pResource; - resource_t *next; - - pResource = (*cl_resourcesonhand).pNext; - - while (pResource && pResource != cl_resourcesonhand) - { - next = pResource->pNext; - - if ((pResource->ucFlags & RES_PRECACHED)) - { - switch (pResource->type) - { - case t_sound: - { - FILESYSTEM_ANY_WRITE(pResource->szFileName, strlen(pResource->szFileName), FileHandle); - FILESYSTEM_ANY_WRITE("\n", 1, FileHandle); - break; - } - - case t_model: - { - if (pResource->szFileName[0] != '*') - { - FILESYSTEM_ANY_WRITE(pResource->szFileName, strlen(pResource->szFileName), FileHandle); - FILESYSTEM_ANY_WRITE("\n", 1, FileHandle); - } - - break; - } - case t_generic: - { - FILESYSTEM_ANY_WRITE(pResource->szFileName, strlen(pResource->szFileName), FileHandle); - FILESYSTEM_ANY_WRITE("\n", 1, FileHandle); - break; - } - } - } - pResource = next; - } - - FILESYSTEM_ANY_CLOSE(FileHandle); - - gEngfuncs.Con_Printf("FS_Dump_Precaches: Precached resources dumpped into %s.\n", filename.c_str()); + const char* mapname = gEngfuncs.pfnGetLevelName(); + + if (!mapname || !mapname[0]) + { + gEngfuncs.Con_Printf("FS_Dump_Precaches: Cannot dump precache resource list because you are not in an active map!\n"); + return; + } + + std::string filename = mapname; + + filename = filename.substr(0, filename.length() - 4); + + filename = filename + ".dump.res"; + + auto FileHandle = FILESYSTEM_ANY_OPEN(filename.c_str(), "wt"); + + if (!FileHandle) + { + gEngfuncs.Con_Printf("FS_Dump_Precaches: Could not open \"%s\" for writing!\n", filename.c_str()); + return; + } + + resource_t* pResource; + resource_t* next; + + pResource = (*cl_resourcesonhand).pNext; + + while (pResource && pResource != cl_resourcesonhand) + { + next = pResource->pNext; + + if ((pResource->ucFlags & RES_PRECACHED)) + { + switch (pResource->type) + { + case t_sound: + { + FILESYSTEM_ANY_WRITE(pResource->szFileName, strlen(pResource->szFileName), FileHandle); + FILESYSTEM_ANY_WRITE("\n", 1, FileHandle); + break; + } + + case t_model: + { + if (pResource->szFileName[0] != '*') + { + FILESYSTEM_ANY_WRITE(pResource->szFileName, strlen(pResource->szFileName), FileHandle); + FILESYSTEM_ANY_WRITE("\n", 1, FileHandle); + } + + break; + } + case t_generic: + { + FILESYSTEM_ANY_WRITE(pResource->szFileName, strlen(pResource->szFileName), FileHandle); + FILESYSTEM_ANY_WRITE("\n", 1, FileHandle); + break; + } + } + } + pResource = next; + } + + FILESYSTEM_ANY_CLOSE(FileHandle); + + gEngfuncs.Con_Printf("FS_Dump_Precaches: Precached resources dumpped into %s.\n", filename.c_str()); } void HUD_Init(void) { - gExportfuncs.HUD_Init(); + gExportfuncs.HUD_Init(); - gEngfuncs.pfnAddCommand("fs_dump_precaches", FS_Dump_Precaches); + gEngfuncs.pfnAddCommand("fs_dump_precaches", FS_Dump_Precaches); } \ No newline at end of file diff --git a/src/plugins.cpp b/src/plugins.cpp index 724dc19..b9d9a34 100644 --- a/src/plugins.cpp +++ b/src/plugins.cpp @@ -2,52 +2,52 @@ #include "exportfuncs.h" #include "privatehook.h" -cl_exportfuncs_t gExportfuncs = { 0 }; -mh_interface_t* g_pInterface = NULL; -metahook_api_t* g_pMetaHookAPI = NULL; -mh_enginesave_t* g_pMetaSave = NULL; -IFileSystem* g_pFileSystem = NULL; +cl_exportfuncs_t gExportfuncs = {0}; +mh_interface_t* g_pInterface = NULL; +metahook_api_t* g_pMetaHookAPI = NULL; +mh_enginesave_t* g_pMetaSave = NULL; +IFileSystem* g_pFileSystem = NULL; IFileSystem_HL25* g_pFileSystem_HL25 = NULL; -int g_iEngineType = 0; +int g_iEngineType = 0; DWORD g_dwEngineBuildnum = 0; -mh_dll_info_t g_EngineDLLInfo = { 0 }; +mh_dll_info_t g_EngineDLLInfo = {0}; -void IPluginsV4::Init(metahook_api_t *pAPI, mh_interface_t *pInterface, mh_enginesave_t *pSave) +void IPluginsV4::Init(metahook_api_t* pAPI, mh_interface_t* pInterface, mh_enginesave_t* pSave) { - g_pInterface = pInterface; - g_pMetaHookAPI = pAPI; - g_pMetaSave = pSave; + g_pInterface = pInterface; + g_pMetaHookAPI = pAPI; + g_pMetaSave = pSave; } void IPluginsV4::Shutdown(void) { } -void IPluginsV4::LoadEngine(cl_enginefunc_t *pEngfuncs) +void IPluginsV4::LoadEngine(cl_enginefunc_t* pEngfuncs) { - g_pFileSystem = g_pInterface->FileSystem; - if (!g_pFileSystem) - { - g_pFileSystem_HL25 = g_pInterface->FileSystem_HL25; - } + g_pFileSystem = g_pInterface->FileSystem; + if (!g_pFileSystem) + { + g_pFileSystem_HL25 = g_pInterface->FileSystem_HL25; + } - g_iEngineType = g_pMetaHookAPI->GetEngineType(); - g_dwEngineBuildnum = g_pMetaHookAPI->GetEngineBuildnum(); + g_iEngineType = g_pMetaHookAPI->GetEngineType(); + g_dwEngineBuildnum = g_pMetaHookAPI->GetEngineBuildnum(); - g_EngineDLLInfo.ImageBase = g_pMetaHookAPI->GetEngineBase(); + g_EngineDLLInfo.ImageBase = g_pMetaHookAPI->GetEngineBase(); - memcpy(&gEngfuncs, pEngfuncs, sizeof(gEngfuncs)); + memcpy(&gEngfuncs, pEngfuncs, sizeof(gEngfuncs)); - Engine_FillAddress(); + Engine_FillAddress(); } -void IPluginsV4::LoadClient(cl_exportfuncs_t *pExportFunc) +void IPluginsV4::LoadClient(cl_exportfuncs_t* pExportFunc) { - memcpy(&gExportfuncs, pExportFunc, sizeof(gExportfuncs)); + memcpy(&gExportfuncs, pExportFunc, sizeof(gExportfuncs)); - pExportFunc->HUD_Init = HUD_Init; + pExportFunc->HUD_Init = HUD_Init; } void IPluginsV4::ExitGame(int iResult) @@ -55,24 +55,23 @@ void IPluginsV4::ExitGame(int iResult) } const char completeVersion[] = + { + BUILD_YEAR_CH0, BUILD_YEAR_CH1, BUILD_YEAR_CH2, BUILD_YEAR_CH3, + '-', + BUILD_MONTH_CH0, BUILD_MONTH_CH1, + '-', + BUILD_DAY_CH0, BUILD_DAY_CH1, + 'T', + BUILD_HOUR_CH0, BUILD_HOUR_CH1, + ':', + BUILD_MIN_CH0, BUILD_MIN_CH1, + ':', + BUILD_SEC_CH0, BUILD_SEC_CH1, + '\0'}; + +const char* IPluginsV4::GetVersion(void) { - BUILD_YEAR_CH0, BUILD_YEAR_CH1, BUILD_YEAR_CH2, BUILD_YEAR_CH3, - '-', - BUILD_MONTH_CH0, BUILD_MONTH_CH1, - '-', - BUILD_DAY_CH0, BUILD_DAY_CH1, - 'T', - BUILD_HOUR_CH0, BUILD_HOUR_CH1, - ':', - BUILD_MIN_CH0, BUILD_MIN_CH1, - ':', - BUILD_SEC_CH0, BUILD_SEC_CH1, - '\0' -}; - -const char *IPluginsV4::GetVersion(void) -{ - return completeVersion; + return completeVersion; } EXPOSE_SINGLE_INTERFACE(IPluginsV4, IPluginsV4, METAHOOK_PLUGIN_API_VERSION_V4); \ No newline at end of file diff --git a/src/plugins.h b/src/plugins.h index c47e860..7b8ed2a 100644 --- a/src/plugins.h +++ b/src/plugins.h @@ -5,37 +5,48 @@ class IFileSystem; class IFileSystem_HL25; -extern IFileSystem* g_pFileSystem; +extern IFileSystem* g_pFileSystem; extern IFileSystem_HL25* g_pFileSystem_HL25; -extern int g_iEngineType; +extern int g_iEngineType; extern DWORD g_dwEngineBuildnum; extern mh_dll_info_t g_EngineDLLInfo; -#define MHPluginName "PrecacheManager" -#define Sys_Error(msg, ...) g_pMetaHookAPI->SysError("[" MHPluginName "] " msg, __VA_ARGS__); -#define Sig_NotFound(name) Sys_Error("Could not found: %s\nEngine buildnum: %d", #name, g_dwEngineBuildnum); -#define Sig_VarNotFound(name) if(!name) Sig_NotFound(name) -#define Sig_AddrNotFound(name) if(!addr) Sig_NotFound(name) -#define Sig_FuncNotFound(name) if(!gPrivateFuncs.name) Sig_NotFound(name) - -#define Sig_Length(a) (sizeof(a)-1) -#define Search_Pattern(sig, dllinfo) g_pMetaHookAPI->SearchPattern(dllinfo.TextBase, dllinfo.TextSize, sig, Sig_Length(sig)) -#define Search_Pattern_Data(sig, dllinfo) g_pMetaHookAPI->SearchPattern(dllinfo.DataBase, dllinfo.DataSize, sig, Sig_Length(sig)) -#define Search_Pattern_Rdata(sig, dllinfo) g_pMetaHookAPI->SearchPattern(dllinfo.RdataBase, dllinfo.RdataSize, sig, Sig_Length(sig)) -#define Search_Pattern_From_Size(fn, size, sig) g_pMetaHookAPI->SearchPattern((void *)(fn), size, sig, Sig_Length(sig)) -#define Search_Pattern_From(fn, sig, dllinfo) g_pMetaHookAPI->SearchPattern((void *)(fn), ((PUCHAR)dllinfo.TextBase + dllinfo.TextSize) - (PUCHAR)(fn), sig, Sig_Length(sig)) - -#define Search_Pattern_NoWildCard(sig, dllinfo) g_pMetaHookAPI->SearchPatternNoWildCard(dllinfo.TextBase, dllinfo.TextSize, sig, Sig_Length(sig)) -#define Search_Pattern_NoWildCard_Data(sig, dllinfo) g_pMetaHookAPI->SearchPatternNoWildCard(dllinfo.DataBase, dllinfo.DataSize, sig, Sig_Length(sig)) +#define MHPluginName "PrecacheManager" +#define Sys_Error(msg, ...) g_pMetaHookAPI->SysError("[" MHPluginName "] " msg, __VA_ARGS__); +#define Sig_NotFound(name) Sys_Error("Could not found: %s\nEngine buildnum: %d", #name, g_dwEngineBuildnum); +#define Sig_VarNotFound(name) \ + if (!name) Sig_NotFound(name) +#define Sig_AddrNotFound(name) \ + if (!addr) Sig_NotFound(name) +#define Sig_FuncNotFound(name) \ + if (!gPrivateFuncs.name) Sig_NotFound(name) + +#define Sig_Length(a) (sizeof(a) - 1) +#define Search_Pattern(sig, dllinfo) g_pMetaHookAPI->SearchPattern(dllinfo.TextBase, dllinfo.TextSize, sig, Sig_Length(sig)) +#define Search_Pattern_Data(sig, dllinfo) g_pMetaHookAPI->SearchPattern(dllinfo.DataBase, dllinfo.DataSize, sig, Sig_Length(sig)) +#define Search_Pattern_Rdata(sig, dllinfo) g_pMetaHookAPI->SearchPattern(dllinfo.RdataBase, dllinfo.RdataSize, sig, Sig_Length(sig)) +#define Search_Pattern_From_Size(fn, size, sig) g_pMetaHookAPI->SearchPattern((void*)(fn), size, sig, Sig_Length(sig)) +#define Search_Pattern_From(fn, sig, dllinfo) g_pMetaHookAPI->SearchPattern((void*)(fn), ((PUCHAR)dllinfo.TextBase + dllinfo.TextSize) - (PUCHAR)(fn), sig, Sig_Length(sig)) + +#define Search_Pattern_NoWildCard(sig, dllinfo) g_pMetaHookAPI->SearchPatternNoWildCard(dllinfo.TextBase, dllinfo.TextSize, sig, Sig_Length(sig)) +#define Search_Pattern_NoWildCard_Data(sig, dllinfo) g_pMetaHookAPI->SearchPatternNoWildCard(dllinfo.DataBase, dllinfo.DataSize, sig, Sig_Length(sig)) #define Search_Pattern_NoWildCard_Rdata(sig, dllinfo) g_pMetaHookAPI->SearchPatternNoWildCard(dllinfo.RdataBase, dllinfo.RdataSize, sig, Sig_Length(sig)) -#define Install_InlineHook(fn) if(!g_phook_##fn) { g_phook_##fn = g_pMetaHookAPI->InlineHook((void *)gPrivateFuncs.fn, fn, (void **)&gPrivateFuncs.fn); } -#define Uninstall_Hook(fn) if(g_phook_##fn){g_pMetaHookAPI->UnHook(g_phook_##fn);g_phook_##fn = NULL;} +#define Install_InlineHook(fn) \ + if (!g_phook_##fn) { g_phook_##fn = g_pMetaHookAPI->InlineHook((void*)gPrivateFuncs.fn, fn, (void**)&gPrivateFuncs.fn); } +#define Uninstall_Hook(fn) \ + if (g_phook_##fn) \ + { \ + g_pMetaHookAPI->UnHook(g_phook_##fn); \ + g_phook_##fn = NULL; \ + } #define GetCallAddress(addr) g_pMetaHookAPI->GetNextCallAddr((PUCHAR)addr, 1) #define RVA_from_VA(name, dllinfo) (ULONG)((ULONG_PTR)name##_VA - (ULONG_PTR)dllinfo.ImageBase) #define VA_from_RVA(name, dllinfo) ((ULONG_PTR)dllinfo.ImageBase + (ULONG_PTR)name##_RVA) -#define Convert_VA_to_RVA(name, dllinfo) if(name##_VA) name##_RVA = ((ULONG_PTR)name##_VA - (ULONG_PTR)dllinfo.ImageBase) -#define Convert_RVA_to_VA(name, dllinfo) if(name##_RVA) name##_VA = (decltype(name##_VA))VA_from_RVA(name, dllinfo) +#define Convert_VA_to_RVA(name, dllinfo) \ + if (name##_VA) name##_RVA = ((ULONG_PTR)name##_VA - (ULONG_PTR)dllinfo.ImageBase) +#define Convert_RVA_to_VA(name, dllinfo) \ + if (name##_RVA) name##_VA = (decltype(name##_VA))VA_from_RVA(name, dllinfo) diff --git a/src/privatehook.cpp b/src/privatehook.cpp index 524a26a..438de47 100644 --- a/src/privatehook.cpp +++ b/src/privatehook.cpp @@ -12,42 +12,42 @@ private_funcs_t gPrivateFuncs = {0}; // and the host's reason for the failure. static void ReportSymbolFailure(PVOID moduleBase, const char* moduleName, const char* symbolName, mh_gamesymbol_status_t status) { - uint64_t crc64 = 0; - mh_gamesymbol_status_t crcSt = g_pMetaHookAPI->GetModuleCRC64(moduleBase, &crc64); - - if (crcSt == MH_GAMESYMBOL_OK) - { - Sys_Error("Failed to resolve \"%s\" (module %s)\nEngine buildnum: %d\nCRC64: %016llx\nReason: %s", - symbolName, moduleName, g_dwEngineBuildnum, (unsigned long long)crc64, g_pMetaHookAPI->GetGameSymbolStatusString(status)); - } - else - { - Sys_Error("Failed to resolve \"%s\" (module %s)\nEngine buildnum: %d\nReason: %s", - symbolName, moduleName, g_dwEngineBuildnum, g_pMetaHookAPI->GetGameSymbolStatusString(status)); - } + uint64_t crc64 = 0; + mh_gamesymbol_status_t crcSt = g_pMetaHookAPI->GetModuleCRC64(moduleBase, &crc64); + + if (crcSt == MH_GAMESYMBOL_OK) + { + Sys_Error("Failed to resolve \"%s\" (module %s)\nEngine buildnum: %d\nCRC64: %016llx\nReason: %s", + symbolName, moduleName, g_dwEngineBuildnum, (unsigned long long)crc64, g_pMetaHookAPI->GetGameSymbolStatusString(status)); + } + else + { + Sys_Error("Failed to resolve \"%s\" (module %s)\nEngine buildnum: %d\nReason: %s", + symbolName, moduleName, g_dwEngineBuildnum, g_pMetaHookAPI->GetGameSymbolStatusString(status)); + } } PVOID GamedataResolvePtr(PVOID moduleBase, const char* moduleName, const char* symbolName, mh_gamesymbol_kind_t kind) { - PVOID address = NULL; - mh_gamesymbol_status_t status = g_pMetaHookAPI->ResolveGameSymbol(moduleBase, symbolName, kind, &address); + PVOID address = NULL; + mh_gamesymbol_status_t status = g_pMetaHookAPI->ResolveGameSymbol(moduleBase, symbolName, kind, &address); - if (status != MH_GAMESYMBOL_OK) - ReportSymbolFailure(moduleBase, moduleName, symbolName, status); + if (status != MH_GAMESYMBOL_OK) + ReportSymbolFailure(moduleBase, moduleName, symbolName, status); - return address; + return address; } void Engine_FillAddress_CL_ResourceOnHand(void) { - // The gamedata global is the list sentinel node itself, so the resolved address - // is exactly what FS_Dump_Precaches walks: start at ->pNext and stop when the - // walk returns here. No extra dereference. - cl_resourcesonhand = (decltype(cl_resourcesonhand)) - GamedataResolvePtr(g_EngineDLLInfo.ImageBase, "engine", "cl_resourcesonhand", MH_GAMESYMBOL_KIND_GLOBAL); + // The gamedata global is the list sentinel node itself, so the resolved address + // is exactly what FS_Dump_Precaches walks: start at ->pNext and stop when the + // walk returns here. No extra dereference. + cl_resourcesonhand = (decltype(cl_resourcesonhand)) + GamedataResolvePtr(g_EngineDLLInfo.ImageBase, "engine", "cl_resourcesonhand", MH_GAMESYMBOL_KIND_GLOBAL); } void Engine_FillAddress(void) { - Engine_FillAddress_CL_ResourceOnHand(); + Engine_FillAddress_CL_ResourceOnHand(); } diff --git a/src/privatehook.h b/src/privatehook.h index cfce25f..0cb3d4c 100644 --- a/src/privatehook.h +++ b/src/privatehook.h @@ -2,38 +2,38 @@ typedef struct { - qboolean(*CL_PrecacheResources)(); -}private_funcs_t; + qboolean (*CL_PrecacheResources)(); +} private_funcs_t; typedef enum { - t_sound = 0, - t_skin, - t_model, - t_decal, - t_generic, - t_eventscript, - t_world, // Fake type for world, is really t_model + t_sound = 0, + t_skin, + t_model, + t_decal, + t_generic, + t_eventscript, + t_world, // Fake type for world, is really t_model } resourcetype_t; typedef struct resource_s { - char szFileName[64]; // File name to download/precache. - resourcetype_t type; // t_sound, t_skin, t_model, t_decal. - int nIndex; // For t_decals - int nDownloadSize; // Size in Bytes if this must be downloaded. - unsigned char ucFlags; - - // For handling client to client resource propagation - unsigned char rgucMD5_hash[16]; // To determine if we already have it. - unsigned char playernum; // Which player index this resource is associated with, if it's a custom resource. - - unsigned char rguc_reserved[32]; // For future expansion - struct resource_s *pNext; // Next in chain. - struct resource_s *pPrev; + char szFileName[64]; // File name to download/precache. + resourcetype_t type; // t_sound, t_skin, t_model, t_decal. + int nIndex; // For t_decals + int nDownloadSize; // Size in Bytes if this must be downloaded. + unsigned char ucFlags; + + // For handling client to client resource propagation + unsigned char rgucMD5_hash[16]; // To determine if we already have it. + unsigned char playernum; // Which player index this resource is associated with, if it's a custom resource. + + unsigned char rguc_reserved[32]; // For future expansion + struct resource_s* pNext; // Next in chain. + struct resource_s* pPrev; } resource_t; -extern resource_t *cl_resourcesonhand; +extern resource_t* cl_resourcesonhand; //Resolve a gamedata symbol for a module. A miss is fatal: it reports the symbol, //its owning module, the engine buildnum, the module CRC64 and the host's reason.