summaryrefslogtreecommitdiffstats
path: root/src/hooks.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-06 16:19:25 +0100
committersalmonik <salmonik@tuta.io>2026-11-06 16:19:25 +0100
commit9f0724dcd25a06c5674d30d045dc485a341253b1 (patch)
treee7587dd03c0b164113d3b879b18d81fccf332c05 /src/hooks.cpp
parentChams: leave engine-forced material passes alone (diff)
downloadhl2h-9f0724dcd25a06c5674d30d045dc485a341253b1.tar.gz
hl2h-9f0724dcd25a06c5674d30d045dc485a341253b1.zip
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).
Diffstat (limited to '')
-rw-r--r--src/hooks.cpp59
1 files changed, 59 insertions, 0 deletions
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 @@
1// hooks.cpp — vtable hook installation and teardown bookkeeping.
2#include "hl2h.h"
3
4#include <mutex>
5#include <vector>
6
7namespace {
8
9struct Installed {
10 void *iface;
11 void **old_vt;
12};
13
14std::mutex g_hook_mu;
15std::vector<Installed> g_installed;
16
17} // namespace
18
19bool hooks_install_vtable(void *iface, size_t slots, const VtablePatch *patches,
20 int count) {
21 if (!iface || !patches || count <= 0)
22 return false;
23 void **old = *(void ***)iface;
24 if (!old)
25 return false;
26 for (int i = 0; i < count; i++) {
27 if (patches[i].slot < 0 || (size_t)patches[i].slot >= slots) {
28 logf("hooks: slot %d out of range (table has %u)", patches[i].slot,
29 (unsigned)slots);
30 return false;
31 }
32 }
33
34 void **clone = vtable_clone(iface, slots);
35 if (!clone)
36 return false;
37 for (int i = 0; i < count; i++) {
38 if (patches[i].original)
39 *patches[i].original = old[patches[i].slot];
40 clone[patches[i].slot] = patches[i].replacement;
41 }
42
43 std::lock_guard<std::mutex> lock(g_hook_mu);
44 *(void ***)iface = clone;
45 g_installed.push_back({iface, old});
46 return true;
47}
48
49void hooks_restore_all() {
50 std::lock_guard<std::mutex> lock(g_hook_mu);
51 for (auto it = g_installed.rbegin(); it != g_installed.rend(); ++it)
52 *(void ***)it->iface = it->old_vt;
53 g_installed.clear();
54}
55
56int hooks_installed_count() {
57 std::lock_guard<std::mutex> lock(g_hook_mu);
58 return (int)g_installed.size();
59}