From 9f0724dcd25a06c5674d30d045dc485a341253b1 Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 6 Nov 2026 16:19:25 +0100 Subject: Hooks: central vtable install with restore support Move vtable patching into hooks.cpp: one call clones the table, validates every slot, records the originals and installs the clone. Installs happen from the setup, game and paint threads, so the bookkeeping is mutex-protected. Client, CInput, IVModelRender, IStudioRender and ISurface all use it, and hooks_restore_all() can now put every interface back (previously impossible). --- src/hooks.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/hooks.cpp (limited to 'src/hooks.cpp') diff --git a/src/hooks.cpp b/src/hooks.cpp new file mode 100644 index 0000000..215ecfd --- /dev/null +++ b/src/hooks.cpp @@ -0,0 +1,59 @@ +// hooks.cpp — vtable hook installation and teardown bookkeeping. +#include "hl2h.h" + +#include +#include + +namespace { + +struct Installed { + void *iface; + void **old_vt; +}; + +std::mutex g_hook_mu; +std::vector g_installed; + +} // namespace + +bool hooks_install_vtable(void *iface, size_t slots, const VtablePatch *patches, + int count) { + if (!iface || !patches || count <= 0) + return false; + void **old = *(void ***)iface; + if (!old) + return false; + for (int i = 0; i < count; i++) { + if (patches[i].slot < 0 || (size_t)patches[i].slot >= slots) { + logf("hooks: slot %d out of range (table has %u)", patches[i].slot, + (unsigned)slots); + return false; + } + } + + void **clone = vtable_clone(iface, slots); + if (!clone) + return false; + for (int i = 0; i < count; i++) { + if (patches[i].original) + *patches[i].original = old[patches[i].slot]; + clone[patches[i].slot] = patches[i].replacement; + } + + std::lock_guard lock(g_hook_mu); + *(void ***)iface = clone; + g_installed.push_back({iface, old}); + return true; +} + +void hooks_restore_all() { + std::lock_guard lock(g_hook_mu); + for (auto it = g_installed.rbegin(); it != g_installed.rend(); ++it) + *(void ***)it->iface = it->old_vt; + g_installed.clear(); +} + +int hooks_installed_count() { + std::lock_guard lock(g_hook_mu); + return (int)g_installed.size(); +} -- cgit v1.2.3