summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-03 22:33:56 +0100
committersalmonik <salmonik@tuta.io>2026-11-03 22:33:56 +0100
commit1ce7a7d3862bed06e27ffbafb92dac6a26bfba7b (patch)
treef8ddbc02cb6ccf7a069197612467a327c206a87a
parentWorld: add Fullbright visual feature (diff)
downloadhl2h-1ce7a7d3862bed06e27ffbafb92dac6a26bfba7b.tar.gz
hl2h-1ce7a7d3862bed06e27ffbafb92dac6a26bfba7b.zip
Fix startup crash: use ClientCmd for fullbright; sanitize owner netvars
- Poking VEngineCvar004/ConVar vtables directly crashed before the main menu (ConVar uses a secondary IConVar vtable). Use the stable IVEngineClient ClientCmd slot 7 for mat_fullbright instead. - Reject out-of-range m_hOwnerEntity/m_hOwner offsets: the resolver found a bogus negative owner offset (-136296061), which could make item-ESP weapon ownership read wild memory.
-rw-r--r--src/hl2h.cpp34
-rw-r--r--src/netvars.cpp8
2 files changed, 15 insertions, 27 deletions
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index ebb9b14..375cd5a 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -131,32 +131,16 @@ static int g_modified_logged = 0;
131// GetName, GetHelpText, IsRegistered, GetDLLIdentifier; ConVar then adds 131// GetName, GetHelpText, IsRegistered, GetDLLIdentifier; ConVar then adds
132// SetValue(const char*), SetValue(float), SetValue(int) -> slot 11. 132// SetValue(const char*), SetValue(float), SetValue(int) -> slot 11.
133bool cvar_set_int(const char *name, int value) { 133bool cvar_set_int(const char *name, int value) {
134 if (!name) 134 if (!name || !g_iface.engine)
135 return false; 135 return false;
136 if (g_iface.cvar) { 136 // Use the stable IVEngineClient ClientCmd slot rather than poking ConVar's
137 using FindVarFn = void *(*)(void *, const char *); 137 // vtable; the installed VEngineCvar004 layout differs enough to crash.
138 void *var = vfunc<FindVarFn>(g_iface.cvar, 12)(g_iface.cvar, name); 138 char cmd[96];
139 if (var) { 139 snprintf(cmd, sizeof(cmd), "%s %d", name, value);
140 using GetNameFn = const char *(*)(void *); 140 using CmdFn = void (*)(void *, const char *);
141 const char *got = vfunc<GetNameFn>(var, 5)(var); 141 vfunc<CmdFn>(g_iface.engine, 7)(g_iface.engine, cmd);
142 if (got && strcmp(got, name) == 0) { 142 logd("cvar: command '%s'", cmd);
143 using SetIntFn = void (*)(void *, int); 143 return true;
144 vfunc<SetIntFn>(var, 11)(var, value);
145 return true;
146 }
147 }
148 }
149 // Fallback for an engine that does not expose VEngineCvar004: ClientCmd
150 // slot 7. Cheat-protected cvars may still be rejected.
151 if (g_iface.engine) {
152 char cmd[96];
153 snprintf(cmd, sizeof(cmd), "%s %d", name, value);
154 using CmdFn = void (*)(void *, const char *);
155 vfunc<CmdFn>(g_iface.engine, 7)(g_iface.engine, cmd);
156 logd("cvar: fallback command '%s'", cmd);
157 return true;
158 }
159 return false;
160} 144}
161 145
162void note_modified(const CUserCmd *cmd, int flags, const float *vel) { 146void note_modified(const CUserCmd *cmd, int flags, const float *vel) {
diff --git a/src/netvars.cpp b/src/netvars.cpp
index adb5a6a..834aa2f 100644
--- a/src/netvars.cpp
+++ b/src/netvars.cpp
@@ -93,9 +93,13 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) {
93 g_net.activeweapon < 0) { 93 g_net.activeweapon < 0) {
94 g_net.activeweapon = (int)(base_off + (uint32_t)poff); 94 g_net.activeweapon = (int)(base_off + (uint32_t)poff);
95 } else if (strcmp(pname2, "m_hOwnerEntity") == 0 && g_net.owner < 0) { 95 } else if (strcmp(pname2, "m_hOwnerEntity") == 0 && g_net.owner < 0) {
96 g_net.owner = (int)(base_off + (uint32_t)poff); 96 int off = (int)(base_off + (uint32_t)poff);
97 if (off > 0 && off < 0x2000)
98 g_net.owner = off;
97 } else if (strcmp(pname2, "m_hOwner") == 0 && g_net.weapon_owner < 0) { 99 } else if (strcmp(pname2, "m_hOwner") == 0 && g_net.weapon_owner < 0) {
98 g_net.weapon_owner = (int)(base_off + (uint32_t)poff); 100 int off = (int)(base_off + (uint32_t)poff);
101 if (off > 0 && off < 0x2000)
102 g_net.weapon_owner = off;
99 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { 103 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) {
100 g_net.teamnum = (int)(base_off + (uint32_t)poff); 104 g_net.teamnum = (int)(base_off + (uint32_t)poff);
101 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { 105 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) {