From e35f0dc0005139774533504965995da48a3dc90d Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Nov 2026 17:24:14 +0100 Subject: Netvars: catch array element props and log the walk - Match m_iAmmo/m_hMyWeapons by name prefix so element props such as m_iAmmo[0] are accepted. - Handle them before the nested-table recursion, since RecvPropArray3 may put the element descriptor in m_pDataTable. - Allow name strings outside client.so (engine/server too), and log the first 16 array props plus the first 8 unreadable prop names so the remaining resolution failure is visible in the normal log. --- src/netvars.cpp | 86 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/netvars.cpp b/src/netvars.cpp index 9b7e3c9..6a34ee5 100644 --- a/src/netvars.cpp +++ b/src/netvars.cpp @@ -6,7 +6,7 @@ // ClientClass (2004-era): CreateFn@0, CreateEventFn@4, Name@8, RecvTable@0xC, Next@0x10 static bool module_string(uintptr_t p, char *out, size_t outn) { - if (!g_client.contains(p)) + if (!g_client.contains(p) && !g_engine.contains(p) && !g_server.contains(p)) return false; const char *s = (const char *)p; size_t i = 0; @@ -61,12 +61,67 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) { uintptr_t ptable = *(uintptr_t *)(prop + 0x28); char pname2[64]; - if (!module_string(pname, pname2, sizeof(pname2))) + if (!module_string(pname, pname2, sizeof(pname2))) { + static int bad_names = 0; + if (bad_names < 8) { + bad_names++; + logf("netvar: unreadable prop name %#lx in %s", (unsigned long)pname, + tname); + } continue; + } if (dump) logd(" [%s] %s type=%d off=%d(0x%x) table=%s array=%s", tname, pname2, ptype, poff, poff, ptable ? "yes" : "no", parray ? "yes" : "no"); + // RecvPropArray3 props can store their element descriptor in either + // m_pArrayProp or (misleadingly) m_pDataTable. Handle the two arrays we + // need before the generic nested-table recursion drops them. + if (g_net.my_weapons < 0 && + strncmp(pname2, "m_hMyWeapons", 12) == 0) { + int off = (int)(base_off + (uint32_t)poff); + uintptr_t elem = parray ? parray : ptable; + if (elem) { + int32_t eoff = *(int32_t *)(elem + 0x2C); + if (eoff) + off = (int)(base_off + (uint32_t)eoff); + } + if (off >= 0x20 && off <= 0x2000) { + g_net.my_weapons = off; + logf("netvar: m_hMyWeapons prop=%s poff=%d elem=%p -> %d", pname2, + poff, (void *)elem, off); + } else { + static int bad = 0; + if (bad < 8) { + bad++; + logf("netvar: m_hMyWeapons prop=%s rejected poff=%d elem=%p off=%d", + pname2, poff, (void *)elem, off); + } + } + continue; + } + if (g_net.ammo < 0 && strncmp(pname2, "m_iAmmo", 7) == 0) { + int off = (int)(base_off + (uint32_t)poff); + uintptr_t elem = parray ? parray : ptable; + if (elem) { + int32_t eoff = *(int32_t *)(elem + 0x2C); + if (eoff) + off = (int)(base_off + (uint32_t)eoff); + } + if (off >= 0x20 && off <= 0x2000) { + g_net.ammo = off; + logf("netvar: m_iAmmo prop=%s poff=%d elem=%p -> %d", pname2, poff, + (void *)elem, off); + } else { + static int bad = 0; + if (bad < 8) { + bad++; + logf("netvar: m_iAmmo prop=%s rejected poff=%d elem=%p off=%d", + pname2, poff, (void *)elem, off); + } + } + continue; + } if (ptable && !parray) { collect_netvars(ptable, base_off + (uint32_t)poff, depth + 1); continue; @@ -75,7 +130,7 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) { static int alogs = 0; if (alogs < 16) { alogs++; - logd("netvar array %s poff=%d eoff=%d base=%d", pname2, poff, + logf("netvar array %s poff=%d eoff=%d base=%d", pname2, poff, *(int32_t *)(parray + 0x2C), (int)base_off); } } @@ -120,31 +175,6 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) { int off = (int)(base_off + (uint32_t)poff); if (off >= 0x20 && off <= 0x2000) g_net.dmg_radius = off; - } else if (strcmp(pname2, "m_hMyWeapons") == 0 && - g_net.my_weapons < 0) { - int off = (int)(base_off + (uint32_t)poff); - if (parray) { - int32_t eoff = *(int32_t *)(parray + 0x2C); - if (eoff) - off = (int)(base_off + (uint32_t)eoff); - } - if (off >= 0x20 && off <= 0x2000) { - g_net.my_weapons = off; - logd("netvar: m_hMyWeapons base_off=%d poff=%d parray=%p -> %d", - (int)base_off, poff, (void *)parray, off); - } - } else if (strcmp(pname2, "m_iAmmo") == 0 && g_net.ammo < 0) { - int off = (int)(base_off + (uint32_t)poff); - if (parray) { - int32_t eoff = *(int32_t *)(parray + 0x2C); - if (eoff) - off = (int)(base_off + (uint32_t)eoff); - } - if (off >= 0x20 && off <= 0x2000) { - g_net.ammo = off; - logd("netvar: m_iAmmo base_off=%d poff=%d parray=%p -> %d", - (int)base_off, poff, (void *)parray, off); - } } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { g_net.teamnum = (int)(base_off + (uint32_t)poff); } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { -- cgit v1.2.3