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/hl2h.cpp | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'src/hl2h.cpp') diff --git a/src/hl2h.cpp b/src/hl2h.cpp index 6697778..354b3e6 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp @@ -1125,20 +1125,17 @@ static bool hkdCreateMove(void *self, int seq, float frametime, bool active) { // DrawPrintText (slot 22) hooked as a fallback text-draw trigger. static int isurface_hooked = 0; if (!isurface_hooked && g_surface) { - void **svt = VTABLE(g_surface); - constexpr size_t VT_SIZE = 256; - void **newsvt = vtable_clone(g_surface, VT_SIZE); - if (!newsvt) { - isurface_hooked = 1; // don't retry every tick - logf("ISurface hook: vtable unavailable"); + VtablePatch patches[] = { + {22, (void *)&hkdDrawPrintText, + reinterpret_cast(&oDrawPrintText)}, + {114, (void *)&hkdPaintTraverseEx, + reinterpret_cast(&oPaintTraverseEx)}, + }; + isurface_hooked = 1; // one attempt only + if (!hooks_install_vtable(g_surface, 256, patches, 2)) { + logf("ISurface hook: vtable patch failed"); return ret; } - oDrawPrintText = (DrawPrintTextFn)svt[22]; - newsvt[22] = (void *)&hkdDrawPrintText; - oPaintTraverseEx = (PaintTraverseExFn)svt[114]; - newsvt[114] = (void *)&hkdPaintTraverseEx; - VTABLE(g_surface) = newsvt; - isurface_hooked = 1; logf("ISurface hooked: DrawPrintText slot 22 orig=%p, PaintTraverseEx slot 114 orig=%p", (void *)oDrawPrintText, (void *)oPaintTraverseEx); } @@ -1147,21 +1144,18 @@ static bool hkdCreateMove(void *self, int seq, float frametime, bool active) { } static void install_hook() { - void **vt = VTABLE(g_iface.client); - constexpr size_t SLOTS = 256; - void **newvt = vtable_clone(g_iface.client, SLOTS); - if (!newvt) { - logf("hook install: client vtable unavailable"); + VtablePatch patches[] = { + {21, (void *)&hkdCreateMove, reinterpret_cast(&oCreateMove)}, + {35, (void *)&hkdFrameStageNotify, + reinterpret_cast(&oFrameStageNotify)}, + }; + if (!hooks_install_vtable(g_iface.client, 256, patches, 2)) { + logf("hook install: client vtable patch failed"); return; } - oCreateMove = (CreateMoveFn)vt[21]; - newvt[21] = (void *)&hkdCreateMove; - oFrameStageNotify = (FrameStageFn)vt[35]; - newvt[35] = (void *)&hkdFrameStageNotify; - VTABLE(g_iface.client) = newvt; - logf("hook installed: CreateMove %p -> %p (orig %p), FrameStageNotify %p " - "-> %p (orig %p)", - vt[21], (void *)&hkdCreateMove, (void *)oCreateMove, vt[35], + logf("hook installed: CreateMove -> %p (orig %p), FrameStageNotify -> %p " + "(orig %p)", + (void *)&hkdCreateMove, (void *)oCreateMove, (void *)&hkdFrameStageNotify, (void *)oFrameStageNotify); } -- cgit v1.2.3