diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 0000000..a451232 --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1,9 @@ +# Repository-relative exclusions for shared FormatValidation. +# Only src/, include/, and tests/ are selected; dependencies and artifacts are excluded. +**/thirdparty/** +**/build/** +**/install/** + +# Unmodified Austin Appleby public-domain third-party implementation. +src/MurmurHash2.cpp +src/MurmurHash2.h 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 a743559..2f7db86 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(StudioEvents LANGUAGES CXX) @@ -88,3 +94,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 242463a..d6fda94 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,36 @@ python scripts\validate-gamedata.py install\x86\Release\svencoop\metahook\gameda ## License Licensed under the [MIT License](LICENSE). MurmurHash2 retains Austin Appleby's public-domain notice; each SDK dependency retains its own license. + +## 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 5a4f3f5..64f0c29 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -54,3 +54,33 @@ python scripts\validate-gamedata.py install\x86\Release\svencoop\metahook\gameda ## 许可证 采用 [MIT License](LICENSE)。MurmurHash2 保留 Austin Appleby 的公有领域声明,各 SDK 依赖保留其原有许可证。 + +## 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..c2d3f81 --- /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(studioevents_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(studioevents_format_validation) + set(_format_validation_source "${studioevents_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(StudioEvents "${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/src/exportfuncs.cpp b/src/exportfuncs.cpp index 4fc7dd2..7c63e90 100644 --- a/src/exportfuncs.cpp +++ b/src/exportfuncs.cpp @@ -19,30 +19,30 @@ #include "privatehook.h" #include "exportfuncs.h" -cl_enginefunc_t gEngfuncs; -engine_studio_api_t IEngineStudio; +cl_enginefunc_t gEngfuncs; +engine_studio_api_t IEngineStudio; r_studio_interface_t** gpStudioInterface; -cvar_t* cl_studiosnd_anti_spam_diff = NULL; -cvar_t* cl_studiosnd_anti_spam_same = NULL; +cvar_t* cl_studiosnd_anti_spam_diff = NULL; +cvar_t* cl_studiosnd_anti_spam_same = NULL; cvar_t* cl_studiosnd_anti_spam_delay = NULL; -cvar_t* cl_studiosnd_block_player = NULL; -cvar_t* cl_studiosnd_debug = NULL; +cvar_t* cl_studiosnd_block_player = NULL; +cvar_t* cl_studiosnd_debug = NULL; typedef struct studio_event_sound_s { - studio_event_sound_s(const char* n, int e, int f, float t) - { - strcpy(name, n); - entindex = e; - frame = f; - time = t; - } - char name[64]; - int entindex; - int frame; - float time; -}studio_event_sound_t; + studio_event_sound_s(const char* n, int e, int f, float t) + { + strcpy(name, n); + entindex = e; + frame = f; + time = t; + } + char name[64]; + int entindex; + int frame; + float time; +} studio_event_sound_t; static std::vector g_StudioEventSoundPlayed; static std::vector g_StudioEventSoundDelayed; @@ -52,244 +52,244 @@ static std::unordered_set g_StudioEventSourceModelWhitelist; const char* EngineStudio_GetCurrentRenderModelName() { - if (!r_model) - return ""; + if (!r_model) + return ""; - if (!(*r_model)) - return ""; + if (!(*r_model)) + return ""; - return (*r_model)->name; + return (*r_model)->name; } uint32_t CalcSoundNameHash(const char* name) { - uint32_t seed = 0; - uint32_t result = MurmurHash2(name, strlen(name), seed); + uint32_t seed = 0; + uint32_t result = MurmurHash2(name, strlen(name), seed); - return result; + return result; } static void LoadWhitelist(std::unordered_set& whitelist, const char* filePath, const char* whitelistName) { - auto hFileHandle = FILESYSTEM_ANY_OPEN(filePath, "rt"); - if (hFileHandle) - { - whitelist.clear(); - - char szReadLine[256]; - while (!FILESYSTEM_ANY_EOF(hFileHandle)) - { - FILESYSTEM_ANY_READLINE(szReadLine, sizeof(szReadLine) - 1, hFileHandle); - szReadLine[sizeof(szReadLine) - 1] = 0; - - // Parse line and extract name - bool quoted = false; - char token[256]; - char* p = szReadLine; - - p = FILESYSTEM_ANY_PARSEFILE(p, token, "ed); - if (token[0]) - { - // Calculate hash and insert into set (set automatically handles duplicates) - uint32_t hash = CalcSoundNameHash(token); - whitelist.insert(hash); - } - } - - FILESYSTEM_ANY_CLOSE(hFileHandle); - - gEngfuncs.Con_DPrintf("[StudioEvents] Loaded %d %s from \"%s\".\n", whitelist.size(), whitelistName, filePath); - } - else - { - gEngfuncs.Con_DPrintf("[StudioEvents] %s file \"%s\" not found.\n", whitelistName, filePath); - } + auto hFileHandle = FILESYSTEM_ANY_OPEN(filePath, "rt"); + if (hFileHandle) + { + whitelist.clear(); + + char szReadLine[256]; + while (!FILESYSTEM_ANY_EOF(hFileHandle)) + { + FILESYSTEM_ANY_READLINE(szReadLine, sizeof(szReadLine) - 1, hFileHandle); + szReadLine[sizeof(szReadLine) - 1] = 0; + + // Parse line and extract name + bool quoted = false; + char token[256]; + char* p = szReadLine; + + p = FILESYSTEM_ANY_PARSEFILE(p, token, "ed); + if (token[0]) + { + // Calculate hash and insert into set (set automatically handles duplicates) + uint32_t hash = CalcSoundNameHash(token); + whitelist.insert(hash); + } + } + + FILESYSTEM_ANY_CLOSE(hFileHandle); + + gEngfuncs.Con_DPrintf("[StudioEvents] Loaded %d %s from \"%s\".\n", whitelist.size(), whitelistName, filePath); + } + else + { + gEngfuncs.Con_DPrintf("[StudioEvents] %s file \"%s\" not found.\n", whitelistName, filePath); + } } void HUD_Init(void) { - gExportfuncs.HUD_Init(); - - cl_studiosnd_anti_spam_diff = gEngfuncs.pfnRegisterVariable("cl_studiosnd_anti_spam_diff", "0.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); - cl_studiosnd_anti_spam_same = gEngfuncs.pfnRegisterVariable("cl_studiosnd_anti_spam_same", "1.0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); - cl_studiosnd_anti_spam_delay = gEngfuncs.pfnRegisterVariable("cl_studiosnd_anti_spam_delay", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); - cl_studiosnd_block_player = gEngfuncs.pfnRegisterVariable("cl_studiosnd_block_player", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); - cl_studiosnd_debug = gEngfuncs.pfnRegisterVariable("cl_studiosnd_debug", "0", FCVAR_CLIENTDLL); - - g_StudioEventSoundPlayed.clear(); - - LoadWhitelist(g_StudioEventSoundWhitelist, "studioevents/sound_whitelist.txt", "whitelisted sounds"); - LoadWhitelist(g_StudioEventSourceModelWhitelist, "studioevents/sourcemodel_whitelist.txt", "whitelisted source models"); + gExportfuncs.HUD_Init(); + + cl_studiosnd_anti_spam_diff = gEngfuncs.pfnRegisterVariable("cl_studiosnd_anti_spam_diff", "0.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); + cl_studiosnd_anti_spam_same = gEngfuncs.pfnRegisterVariable("cl_studiosnd_anti_spam_same", "1.0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); + cl_studiosnd_anti_spam_delay = gEngfuncs.pfnRegisterVariable("cl_studiosnd_anti_spam_delay", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); + cl_studiosnd_block_player = gEngfuncs.pfnRegisterVariable("cl_studiosnd_block_player", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE); + cl_studiosnd_debug = gEngfuncs.pfnRegisterVariable("cl_studiosnd_debug", "0", FCVAR_CLIENTDLL); + + g_StudioEventSoundPlayed.clear(); + + LoadWhitelist(g_StudioEventSoundWhitelist, "studioevents/sound_whitelist.txt", "whitelisted sounds"); + LoadWhitelist(g_StudioEventSourceModelWhitelist, "studioevents/sourcemodel_whitelist.txt", "whitelisted source models"); } int HUD_VidInit(void) { - g_StudioEventSoundPlayed.clear(); - g_StudioEventSoundDelayed.clear(); + g_StudioEventSoundPlayed.clear(); + g_StudioEventSoundDelayed.clear(); - return gExportfuncs.HUD_VidInit(); + return gExportfuncs.HUD_VidInit(); } void HUD_Frame(double a1) { - gExportfuncs.HUD_Frame(a1); - - auto local = gEngfuncs.GetLocalPlayer(); - - if (!local) - { - return; - } - - auto clientTime = gEngfuncs.GetClientTime(); - - auto itor = g_StudioEventSoundDelayed.begin(); - while (itor != g_StudioEventSoundDelayed.end()) - { - if (clientTime > itor->time) - { - auto ent = gEngfuncs.GetEntityByIndex(itor->entindex); - - if (ent && ent->curstate.messagenum == local->curstate.messagenum)//TODO: change to cl_parsecount? player not emitted will get incorrect messagenum - { - mstudioevent_s ev; - ev.event = 5004; - ev.frame = itor->frame; - strcpy(ev.options, itor->name); - ev.type = 0; - - HUD_StudioEvent(&ev, ent); - } - - itor = g_StudioEventSoundDelayed.erase(itor); - } - else - { - itor++; - } - } + gExportfuncs.HUD_Frame(a1); + + auto local = gEngfuncs.GetLocalPlayer(); + + if (!local) + { + return; + } + + auto clientTime = gEngfuncs.GetClientTime(); + + auto itor = g_StudioEventSoundDelayed.begin(); + while (itor != g_StudioEventSoundDelayed.end()) + { + if (clientTime > itor->time) + { + auto ent = gEngfuncs.GetEntityByIndex(itor->entindex); + + if (ent && ent->curstate.messagenum == local->curstate.messagenum) //TODO: change to cl_parsecount? player not emitted will get incorrect messagenum + { + mstudioevent_s ev; + ev.event = 5004; + ev.frame = itor->frame; + strcpy(ev.options, itor->name); + ev.type = 0; + + HUD_StudioEvent(&ev, ent); + } + + itor = g_StudioEventSoundDelayed.erase(itor); + } + else + { + itor++; + } + } } void HUD_StudioEvent(const struct mstudioevent_s* ev, const struct cl_entity_s* ent) { - if (ev->event == 5004 && ev->options[0]) - { - // Check whitelist first - whitelisted sounds or source models bypass all checks - - const char* soundSourceModelName = EngineStudio_GetCurrentRenderModelName(); - const char* soundName = ev->options; - - // Check sound name whitelist - uint32_t soundHash = CalcSoundNameHash(soundName); - if (g_StudioEventSoundWhitelist.find(soundHash) != g_StudioEventSoundWhitelist.end()) - { - if (cl_studiosnd_debug->value) - gEngfuncs.Con_Printf("[StudioEvents] Sound whitelisted: %s\n", ev->options); - - gExportfuncs.HUD_StudioEvent(ev, ent); - return; - } - - // Check source model whitelist - uint32_t modelHash = CalcSoundNameHash(soundSourceModelName); - if (g_StudioEventSourceModelWhitelist.find(modelHash) != g_StudioEventSourceModelWhitelist.end()) - { - if (cl_studiosnd_debug->value) - gEngfuncs.Con_Printf("[StudioEvents] Source model whitelisted: %s (sound: %s)\n", soundSourceModelName, ev->options); - - gExportfuncs.HUD_StudioEvent(ev, ent); - return; - } - - if (cl_studiosnd_block_player->value > 0 && ent->player) - { - if (cl_studiosnd_debug->value) - gEngfuncs.Con_Printf("[StudioEvents] Blocked %s\n", ev->options); - - return; - } - - float clientTime = (float)gEngfuncs.GetClientTime(); - - bool bFound = false; - float max_time = 0; - - auto max_duration = max(cl_studiosnd_anti_spam_diff->value, cl_studiosnd_anti_spam_same->value); - - auto itor = g_StudioEventSoundPlayed.begin(); - while (itor != g_StudioEventSoundPlayed.end()) - { - if (clientTime > itor->time + max_duration) - { - itor = g_StudioEventSoundPlayed.erase(itor); - } - else - { - //Is same sound as before ? - if (itor->entindex == ent->index && itor->frame == ev->frame && !strcmp(itor->name, ev->options)) - { - if (clientTime < itor->time + cl_studiosnd_anti_spam_same->value) - { - bFound = true; - - if (itor->time + cl_studiosnd_anti_spam_same->value > max_time) - max_time = itor->time + cl_studiosnd_anti_spam_same->value; - } - } - else - { - if (clientTime < itor->time + cl_studiosnd_anti_spam_diff->value) - { - bFound = true; - - if (itor->time + cl_studiosnd_anti_spam_diff->value > max_time) - max_time = itor->time + cl_studiosnd_anti_spam_diff->value; - } - } - - itor++; - } - } - - if (bFound) - { - if (cl_studiosnd_anti_spam_delay->value) - { - //blocked - if (cl_studiosnd_debug->value) - gEngfuncs.Con_Printf("[StudioEvents] Delayed %s\n", ev->options); - - g_StudioEventSoundDelayed.emplace_back(ev->options, ent->index, ev->frame, max_time); - } - else - { - //blocked - if (cl_studiosnd_debug->value) - gEngfuncs.Con_Printf("[StudioEvents] Blocked %s\n", ev->options); - } - - return; - } - - //blocked - if (cl_studiosnd_debug->value) - gEngfuncs.Con_Printf("[StudioEvents] Played %s\n", ev->options); - - g_StudioEventSoundPlayed.emplace_back(ev->options, ent->index, ev->frame, clientTime); - } - - gExportfuncs.HUD_StudioEvent(ev, ent); + if (ev->event == 5004 && ev->options[0]) + { + // Check whitelist first - whitelisted sounds or source models bypass all checks + + const char* soundSourceModelName = EngineStudio_GetCurrentRenderModelName(); + const char* soundName = ev->options; + + // Check sound name whitelist + uint32_t soundHash = CalcSoundNameHash(soundName); + if (g_StudioEventSoundWhitelist.find(soundHash) != g_StudioEventSoundWhitelist.end()) + { + if (cl_studiosnd_debug->value) + gEngfuncs.Con_Printf("[StudioEvents] Sound whitelisted: %s\n", ev->options); + + gExportfuncs.HUD_StudioEvent(ev, ent); + return; + } + + // Check source model whitelist + uint32_t modelHash = CalcSoundNameHash(soundSourceModelName); + if (g_StudioEventSourceModelWhitelist.find(modelHash) != g_StudioEventSourceModelWhitelist.end()) + { + if (cl_studiosnd_debug->value) + gEngfuncs.Con_Printf("[StudioEvents] Source model whitelisted: %s (sound: %s)\n", soundSourceModelName, ev->options); + + gExportfuncs.HUD_StudioEvent(ev, ent); + return; + } + + if (cl_studiosnd_block_player->value > 0 && ent->player) + { + if (cl_studiosnd_debug->value) + gEngfuncs.Con_Printf("[StudioEvents] Blocked %s\n", ev->options); + + return; + } + + float clientTime = (float)gEngfuncs.GetClientTime(); + + bool bFound = false; + float max_time = 0; + + auto max_duration = max(cl_studiosnd_anti_spam_diff->value, cl_studiosnd_anti_spam_same->value); + + auto itor = g_StudioEventSoundPlayed.begin(); + while (itor != g_StudioEventSoundPlayed.end()) + { + if (clientTime > itor->time + max_duration) + { + itor = g_StudioEventSoundPlayed.erase(itor); + } + else + { + //Is same sound as before ? + if (itor->entindex == ent->index && itor->frame == ev->frame && !strcmp(itor->name, ev->options)) + { + if (clientTime < itor->time + cl_studiosnd_anti_spam_same->value) + { + bFound = true; + + if (itor->time + cl_studiosnd_anti_spam_same->value > max_time) + max_time = itor->time + cl_studiosnd_anti_spam_same->value; + } + } + else + { + if (clientTime < itor->time + cl_studiosnd_anti_spam_diff->value) + { + bFound = true; + + if (itor->time + cl_studiosnd_anti_spam_diff->value > max_time) + max_time = itor->time + cl_studiosnd_anti_spam_diff->value; + } + } + + itor++; + } + } + + if (bFound) + { + if (cl_studiosnd_anti_spam_delay->value) + { + //blocked + if (cl_studiosnd_debug->value) + gEngfuncs.Con_Printf("[StudioEvents] Delayed %s\n", ev->options); + + g_StudioEventSoundDelayed.emplace_back(ev->options, ent->index, ev->frame, max_time); + } + else + { + //blocked + if (cl_studiosnd_debug->value) + gEngfuncs.Con_Printf("[StudioEvents] Blocked %s\n", ev->options); + } + + return; + } + + //blocked + if (cl_studiosnd_debug->value) + gEngfuncs.Con_Printf("[StudioEvents] Played %s\n", ev->options); + + g_StudioEventSoundPlayed.emplace_back(ev->options, ent->index, ev->frame, clientTime); + } + + gExportfuncs.HUD_StudioEvent(ev, ent); } int HUD_GetStudioModelInterface(int version, struct r_studio_interface_s** ppinterface, struct engine_studio_api_s* pstudio) { - EngineStudio_FillAddress(pstudio, g_MirrorEngineDLLInfo.ImageBase ? g_MirrorEngineDLLInfo : g_EngineDLLInfo, g_EngineDLLInfo); - EngineStudio_InstalHooks(); + EngineStudio_FillAddress(pstudio, g_MirrorEngineDLLInfo.ImageBase ? g_MirrorEngineDLLInfo : g_EngineDLLInfo, g_EngineDLLInfo); + EngineStudio_InstalHooks(); - memcpy(&IEngineStudio, pstudio, sizeof(IEngineStudio)); - gpStudioInterface = ppinterface; + memcpy(&IEngineStudio, pstudio, sizeof(IEngineStudio)); + gpStudioInterface = ppinterface; - int result = gExportfuncs.HUD_GetStudioModelInterface ? gExportfuncs.HUD_GetStudioModelInterface(version, ppinterface, pstudio) : 1; + int result = gExportfuncs.HUD_GetStudioModelInterface ? gExportfuncs.HUD_GetStudioModelInterface(version, ppinterface, pstudio) : 1; - return result; + return result; } \ No newline at end of file diff --git a/src/exportfuncs.h b/src/exportfuncs.h index a9d35b6..b261fa3 100644 --- a/src/exportfuncs.h +++ b/src/exportfuncs.h @@ -4,7 +4,7 @@ #include "cl_entity.h" void HUD_Init(void); -int HUD_VidInit(void); +int HUD_VidInit(void); void HUD_Frame(double clientTime); -void HUD_StudioEvent(const struct mstudioevent_s *ev, const struct cl_entity_s *ent); -int HUD_GetStudioModelInterface(int version, struct r_studio_interface_s** ppinterface, struct engine_studio_api_s* pstudio); \ No newline at end of file +void HUD_StudioEvent(const struct mstudioevent_s* ev, const struct cl_entity_s* ent); +int HUD_GetStudioModelInterface(int version, struct r_studio_interface_s** ppinterface, struct engine_studio_api_s* pstudio); \ No newline at end of file diff --git a/src/plugins.cpp b/src/plugins.cpp index 29593bc..92ce6cc 100644 --- a/src/plugins.cpp +++ b/src/plugins.cpp @@ -2,75 +2,74 @@ #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_MirrorEngineDLLInfo = { 0 }; -mh_dll_info_t g_ClientDLLInfo = { 0 }; -mh_dll_info_t g_MirrorClientDLLInfo = { 0 }; +mh_dll_info_t g_EngineDLLInfo = {0}; +mh_dll_info_t g_MirrorEngineDLLInfo = {0}; +mh_dll_info_t g_ClientDLLInfo = {0}; +mh_dll_info_t g_MirrorClientDLLInfo = {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_iEngineType = g_pMetaHookAPI->GetEngineType(); - g_dwEngineBuildnum = g_pMetaHookAPI->GetEngineBuildnum(); - - g_EngineDLLInfo.ImageBase = g_pMetaHookAPI->GetEngineBase(); - g_EngineDLLInfo.ImageSize = g_pMetaHookAPI->GetEngineSize(); - g_EngineDLLInfo.TextBase = g_pMetaHookAPI->GetSectionByName(g_EngineDLLInfo.ImageBase, ".text\x0\x0\x0", &g_EngineDLLInfo.TextSize); - g_EngineDLLInfo.DataBase = g_pMetaHookAPI->GetSectionByName(g_EngineDLLInfo.ImageBase, ".data\x0\x0\x0", &g_EngineDLLInfo.DataSize); - g_EngineDLLInfo.RdataBase = g_pMetaHookAPI->GetSectionByName(g_EngineDLLInfo.ImageBase, ".rdata\x0\x0", &g_EngineDLLInfo.RdataSize); - - g_MirrorEngineDLLInfo.ImageBase = g_pMetaHookAPI->GetMirrorEngineBase(); - g_MirrorEngineDLLInfo.ImageSize = g_pMetaHookAPI->GetMirrorEngineSize(); - - if (g_MirrorEngineDLLInfo.ImageBase) - { - g_MirrorEngineDLLInfo.TextBase = g_pMetaHookAPI->GetSectionByName(g_MirrorEngineDLLInfo.ImageBase, ".text\x0\x0\x0", &g_MirrorEngineDLLInfo.TextSize); - g_MirrorEngineDLLInfo.DataBase = g_pMetaHookAPI->GetSectionByName(g_MirrorEngineDLLInfo.ImageBase, ".data\x0\x0\x0", &g_MirrorEngineDLLInfo.DataSize); - g_MirrorEngineDLLInfo.RdataBase = g_pMetaHookAPI->GetSectionByName(g_MirrorEngineDLLInfo.ImageBase, ".rdata\x0\x0", &g_MirrorEngineDLLInfo.RdataSize); - } - - memcpy(&gEngfuncs, pEngfuncs, sizeof(gEngfuncs)); - - Engine_FillAddress(g_MirrorEngineDLLInfo.ImageBase ? g_MirrorEngineDLLInfo : g_EngineDLLInfo, g_EngineDLLInfo); - Engine_InstallHooks(); + 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_EngineDLLInfo.ImageBase = g_pMetaHookAPI->GetEngineBase(); + g_EngineDLLInfo.ImageSize = g_pMetaHookAPI->GetEngineSize(); + g_EngineDLLInfo.TextBase = g_pMetaHookAPI->GetSectionByName(g_EngineDLLInfo.ImageBase, ".text\x0\x0\x0", &g_EngineDLLInfo.TextSize); + g_EngineDLLInfo.DataBase = g_pMetaHookAPI->GetSectionByName(g_EngineDLLInfo.ImageBase, ".data\x0\x0\x0", &g_EngineDLLInfo.DataSize); + g_EngineDLLInfo.RdataBase = g_pMetaHookAPI->GetSectionByName(g_EngineDLLInfo.ImageBase, ".rdata\x0\x0", &g_EngineDLLInfo.RdataSize); + + g_MirrorEngineDLLInfo.ImageBase = g_pMetaHookAPI->GetMirrorEngineBase(); + g_MirrorEngineDLLInfo.ImageSize = g_pMetaHookAPI->GetMirrorEngineSize(); + + if (g_MirrorEngineDLLInfo.ImageBase) + { + g_MirrorEngineDLLInfo.TextBase = g_pMetaHookAPI->GetSectionByName(g_MirrorEngineDLLInfo.ImageBase, ".text\x0\x0\x0", &g_MirrorEngineDLLInfo.TextSize); + g_MirrorEngineDLLInfo.DataBase = g_pMetaHookAPI->GetSectionByName(g_MirrorEngineDLLInfo.ImageBase, ".data\x0\x0\x0", &g_MirrorEngineDLLInfo.DataSize); + g_MirrorEngineDLLInfo.RdataBase = g_pMetaHookAPI->GetSectionByName(g_MirrorEngineDLLInfo.ImageBase, ".rdata\x0\x0", &g_MirrorEngineDLLInfo.RdataSize); + } + + memcpy(&gEngfuncs, pEngfuncs, sizeof(gEngfuncs)); + + Engine_FillAddress(g_MirrorEngineDLLInfo.ImageBase ? g_MirrorEngineDLLInfo : g_EngineDLLInfo, g_EngineDLLInfo); + Engine_InstallHooks(); } -void IPluginsV4::LoadClient(cl_exportfuncs_t *pExportFunc) +void IPluginsV4::LoadClient(cl_exportfuncs_t* pExportFunc) { - memcpy(&gExportfuncs, pExportFunc, sizeof(gExportfuncs)); - - pExportFunc->HUD_Init = HUD_Init; - pExportFunc->HUD_VidInit = HUD_VidInit; - pExportFunc->HUD_Frame = HUD_Frame; - pExportFunc->HUD_StudioEvent = HUD_StudioEvent; - pExportFunc->HUD_GetStudioModelInterface = HUD_GetStudioModelInterface; + memcpy(&gExportfuncs, pExportFunc, sizeof(gExportfuncs)); + pExportFunc->HUD_Init = HUD_Init; + pExportFunc->HUD_VidInit = HUD_VidInit; + pExportFunc->HUD_Frame = HUD_Frame; + pExportFunc->HUD_StudioEvent = HUD_StudioEvent; + pExportFunc->HUD_GetStudioModelInterface = HUD_GetStudioModelInterface; } void IPluginsV4::ExitGame(int iResult) @@ -78,24 +77,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 2498e81..e7ea26f 100644 --- a/src/plugins.h +++ b/src/plugins.h @@ -10,10 +10,10 @@ static_assert(METAHOOK_API_VERSION >= 109, "StudioEvents resolves the engine r_m 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; @@ -21,46 +21,57 @@ extern mh_dll_info_t g_MirrorEngineDLLInfo; extern mh_dll_info_t g_ClientDLLInfo; extern mh_dll_info_t g_MirrorClientDLLInfo; -#define MHPluginName "StudioEvents" -#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 MHPluginName "StudioEvents" +#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) //Resolve a required gamedata symbol; a missing symbol is fatal, mirroring the //Sig_VarNotFound policy of the signature-scan locators. //moduleName identifies the module owning the symbol and is echoed by the diagnostic. inline PVOID GamedataResolvePtr(PVOID moduleBase, const char* moduleName, const char* symbolName, mh_gamesymbol_kind_t kind) { - PVOID address = nullptr; - mh_gamesymbol_status_t status = g_pMetaHookAPI->ResolveGameSymbol(moduleBase, symbolName, kind, &address); + PVOID address = nullptr; + mh_gamesymbol_status_t status = g_pMetaHookAPI->ResolveGameSymbol(moduleBase, symbolName, kind, &address); - if (status != MH_GAMESYMBOL_OK) - { - Sys_Error("Could not resolve gamedata symbol: %s (module %s, %s)\nEngine buildnum: %d", - symbolName, moduleName, g_pMetaHookAPI->GetGameSymbolStatusString(status), g_dwEngineBuildnum); - } + if (status != MH_GAMESYMBOL_OK) + { + Sys_Error("Could not resolve gamedata symbol: %s (module %s, %s)\nEngine buildnum: %d", + symbolName, moduleName, g_pMetaHookAPI->GetGameSymbolStatusString(status), g_dwEngineBuildnum); + } - return address; + return address; } -#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 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(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) \ No newline at end of file +#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) \ No newline at end of file diff --git a/src/privatehook.cpp b/src/privatehook.cpp index 9ca73f7..7cf2544 100644 --- a/src/privatehook.cpp +++ b/src/privatehook.cpp @@ -8,58 +8,55 @@ private_funcs_t gPrivateFuncs = {0}; void EngineStudio_FillAddress(struct engine_studio_api_s* pstudio, const mh_dll_info_t& DllInfo, const mh_dll_info_t& RealDllInfo) { - //Engine Studio global slots resolved from gamedata - r_model = (decltype(r_model))GamedataResolvePtr(RealDllInfo.ImageBase, "engine", "r_model", MH_GAMESYMBOL_KIND_GLOBAL); + //Engine Studio global slots resolved from gamedata + r_model = (decltype(r_model))GamedataResolvePtr(RealDllInfo.ImageBase, "engine", "r_model", MH_GAMESYMBOL_KIND_GLOBAL); } void EngineStudio_InstalHooks() { - } void Engine_FillAddress(const mh_dll_info_t& DllInfo, const mh_dll_info_t& RealDllInfo) { - } void Engine_InstallHooks() { - } PVOID ConvertDllInfoSpace(PVOID addr, const mh_dll_info_t& SrcDllInfo, const mh_dll_info_t& TargetDllInfo) { - if ((ULONG_PTR)addr > (ULONG_PTR)SrcDllInfo.ImageBase && (ULONG_PTR)addr < (ULONG_PTR)SrcDllInfo.ImageBase + SrcDllInfo.ImageSize) - { - auto addr_VA = (ULONG_PTR)addr; - auto addr_RVA = RVA_from_VA(addr, SrcDllInfo); + if ((ULONG_PTR)addr > (ULONG_PTR)SrcDllInfo.ImageBase && (ULONG_PTR)addr < (ULONG_PTR)SrcDllInfo.ImageBase + SrcDllInfo.ImageSize) + { + auto addr_VA = (ULONG_PTR)addr; + auto addr_RVA = RVA_from_VA(addr, SrcDllInfo); - return (PVOID)VA_from_RVA(addr, TargetDllInfo); - } + return (PVOID)VA_from_RVA(addr, TargetDllInfo); + } - return nullptr; + return nullptr; } PVOID GetVFunctionFromVFTable(PVOID* vftable, int index, const mh_dll_info_t& DllInfo, const mh_dll_info_t& RealDllInfo, const mh_dll_info_t& OutputDllInfo) { - if ((ULONG_PTR)vftable > (ULONG_PTR)RealDllInfo.ImageBase && (ULONG_PTR)vftable < (ULONG_PTR)RealDllInfo.ImageBase + RealDllInfo.ImageSize) - { - ULONG_PTR vftable_VA = (ULONG_PTR)vftable; - ULONG vftable_RVA = RVA_from_VA(vftable, RealDllInfo); - auto vftable_DllInfo = (decltype(vftable))VA_from_RVA(vftable, DllInfo); - - auto vf_VA = (ULONG_PTR)vftable_DllInfo[index]; - ULONG vf_RVA = RVA_from_VA(vf, DllInfo); - - return (PVOID)VA_from_RVA(vf, OutputDllInfo); - } - else if ((ULONG_PTR)vftable > (ULONG_PTR)DllInfo.ImageBase && (ULONG_PTR)vftable < (ULONG_PTR)DllInfo.ImageBase + DllInfo.ImageSize) - { - auto vf_VA = (ULONG_PTR)vftable[index]; - ULONG vf_RVA = RVA_from_VA(vf, DllInfo); - - return (PVOID)VA_from_RVA(vf, OutputDllInfo); - } - - return vftable[index]; + if ((ULONG_PTR)vftable > (ULONG_PTR)RealDllInfo.ImageBase && (ULONG_PTR)vftable < (ULONG_PTR)RealDllInfo.ImageBase + RealDllInfo.ImageSize) + { + ULONG_PTR vftable_VA = (ULONG_PTR)vftable; + ULONG vftable_RVA = RVA_from_VA(vftable, RealDllInfo); + auto vftable_DllInfo = (decltype(vftable))VA_from_RVA(vftable, DllInfo); + + auto vf_VA = (ULONG_PTR)vftable_DllInfo[index]; + ULONG vf_RVA = RVA_from_VA(vf, DllInfo); + + return (PVOID)VA_from_RVA(vf, OutputDllInfo); + } + else if ((ULONG_PTR)vftable > (ULONG_PTR)DllInfo.ImageBase && (ULONG_PTR)vftable < (ULONG_PTR)DllInfo.ImageBase + DllInfo.ImageSize) + { + auto vf_VA = (ULONG_PTR)vftable[index]; + ULONG vf_RVA = RVA_from_VA(vf, DllInfo); + + return (PVOID)VA_from_RVA(vf, OutputDllInfo); + } + + return vftable[index]; } \ No newline at end of file diff --git a/src/privatehook.h b/src/privatehook.h index 8b2d54d..bbafafa 100644 --- a/src/privatehook.h +++ b/src/privatehook.h @@ -5,15 +5,15 @@ typedef struct { - int unused; -}private_funcs_t; + int unused; +} private_funcs_t; -extern model_t **r_model; +extern model_t** r_model; void EngineStudio_FillAddress(struct engine_studio_api_s* pstudio, const mh_dll_info_t& DllInfo, const mh_dll_info_t& RealDllInfo); void Engine_InstallHooks(void); void EngineStudio_FillAddress(struct engine_studio_api_s* pstudio, const mh_dll_info_t& DllInfo, const mh_dll_info_t& RealDllInfo); void EngineStudio_InstalHooks(); -void Engine_FillAddress(const mh_dll_info_t& DllInfo, const mh_dll_info_t& RealDllInfo); +void Engine_FillAddress(const mh_dll_info_t& DllInfo, const mh_dll_info_t& RealDllInfo); PVOID ConvertDllInfoSpace(PVOID addr, const mh_dll_info_t& SrcDllInfo, const mh_dll_info_t& TargetDllInfo); \ No newline at end of file