summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 17:24:14 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 17:24:14 +0100
commite35f0dc0005139774533504965995da48a3dc90d (patch)
treefe5dfb4d0ad56b49eb42cc98ed4ae5614cc4fea4
parentNetvars: handle RecvPropArray3 array props (diff)
downloadhl2h-e35f0dc0005139774533504965995da48a3dc90d.tar.gz
hl2h-e35f0dc0005139774533504965995da48a3dc90d.zip
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.
-rw-r--r--src/netvars.cpp86
1 files changed, 58 insertions, 28 deletions
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 @@
6// ClientClass (2004-era): CreateFn@0, CreateEventFn@4, Name@8, RecvTable@0xC, Next@0x10 6// ClientClass (2004-era): CreateFn@0, CreateEventFn@4, Name@8, RecvTable@0xC, Next@0x10
7 7
8static bool module_string(uintptr_t p, char *out, size_t outn) { 8static bool module_string(uintptr_t p, char *out, size_t outn) {
9 if (!g_client.contains(p)) 9 if (!g_client.contains(p) && !g_engine.contains(p) && !g_server.contains(p))
10 return false; 10 return false;
11 const char *s = (const char *)p; 11 const char *s = (const char *)p;
12 size_t i = 0; 12 size_t i = 0;
@@ -61,12 +61,67 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) {
61 uintptr_t ptable = *(uintptr_t *)(prop + 0x28); 61 uintptr_t ptable = *(uintptr_t *)(prop + 0x28);
62 62
63 char pname2[64]; 63 char pname2[64];
64 if (!module_string(pname, pname2, sizeof(pname2))) 64 if (!module_string(pname, pname2, sizeof(pname2))) {
65 static int bad_names = 0;
66 if (bad_names < 8) {
67 bad_names++;
68 logf("netvar: unreadable prop name %#lx in %s", (unsigned long)pname,
69 tname);
70 }
65 continue; 71 continue;
72 }
66 73
67 if (dump) 74 if (dump)
68 logd(" [%s] %s type=%d off=%d(0x%x) table=%s array=%s", tname, pname2, 75 logd(" [%s] %s type=%d off=%d(0x%x) table=%s array=%s", tname, pname2,
69 ptype, poff, poff, ptable ? "yes" : "no", parray ? "yes" : "no"); 76 ptype, poff, poff, ptable ? "yes" : "no", parray ? "yes" : "no");
77 // RecvPropArray3 props can store their element descriptor in either
78 // m_pArrayProp or (misleadingly) m_pDataTable. Handle the two arrays we
79 // need before the generic nested-table recursion drops them.
80 if (g_net.my_weapons < 0 &&
81 strncmp(pname2, "m_hMyWeapons", 12) == 0) {
82 int off = (int)(base_off + (uint32_t)poff);
83 uintptr_t elem = parray ? parray : ptable;
84 if (elem) {
85 int32_t eoff = *(int32_t *)(elem + 0x2C);
86 if (eoff)
87 off = (int)(base_off + (uint32_t)eoff);
88 }
89 if (off >= 0x20 && off <= 0x2000) {
90 g_net.my_weapons = off;
91 logf("netvar: m_hMyWeapons prop=%s poff=%d elem=%p -> %d", pname2,
92 poff, (void *)elem, off);
93 } else {
94 static int bad = 0;
95 if (bad < 8) {
96 bad++;
97 logf("netvar: m_hMyWeapons prop=%s rejected poff=%d elem=%p off=%d",
98 pname2, poff, (void *)elem, off);
99 }
100 }
101 continue;
102 }
103 if (g_net.ammo < 0 && strncmp(pname2, "m_iAmmo", 7) == 0) {
104 int off = (int)(base_off + (uint32_t)poff);
105 uintptr_t elem = parray ? parray : ptable;
106 if (elem) {
107 int32_t eoff = *(int32_t *)(elem + 0x2C);
108 if (eoff)
109 off = (int)(base_off + (uint32_t)eoff);
110 }
111 if (off >= 0x20 && off <= 0x2000) {
112 g_net.ammo = off;
113 logf("netvar: m_iAmmo prop=%s poff=%d elem=%p -> %d", pname2, poff,
114 (void *)elem, off);
115 } else {
116 static int bad = 0;
117 if (bad < 8) {
118 bad++;
119 logf("netvar: m_iAmmo prop=%s rejected poff=%d elem=%p off=%d",
120 pname2, poff, (void *)elem, off);
121 }
122 }
123 continue;
124 }
70 if (ptable && !parray) { 125 if (ptable && !parray) {
71 collect_netvars(ptable, base_off + (uint32_t)poff, depth + 1); 126 collect_netvars(ptable, base_off + (uint32_t)poff, depth + 1);
72 continue; 127 continue;
@@ -75,7 +130,7 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) {
75 static int alogs = 0; 130 static int alogs = 0;
76 if (alogs < 16) { 131 if (alogs < 16) {
77 alogs++; 132 alogs++;
78 logd("netvar array %s poff=%d eoff=%d base=%d", pname2, poff, 133 logf("netvar array %s poff=%d eoff=%d base=%d", pname2, poff,
79 *(int32_t *)(parray + 0x2C), (int)base_off); 134 *(int32_t *)(parray + 0x2C), (int)base_off);
80 } 135 }
81 } 136 }
@@ -120,31 +175,6 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) {
120 int off = (int)(base_off + (uint32_t)poff); 175 int off = (int)(base_off + (uint32_t)poff);
121 if (off >= 0x20 && off <= 0x2000) 176 if (off >= 0x20 && off <= 0x2000)
122 g_net.dmg_radius = off; 177 g_net.dmg_radius = off;
123 } else if (strcmp(pname2, "m_hMyWeapons") == 0 &&
124 g_net.my_weapons < 0) {
125 int off = (int)(base_off + (uint32_t)poff);
126 if (parray) {
127 int32_t eoff = *(int32_t *)(parray + 0x2C);
128 if (eoff)
129 off = (int)(base_off + (uint32_t)eoff);
130 }
131 if (off >= 0x20 && off <= 0x2000) {
132 g_net.my_weapons = off;
133 logd("netvar: m_hMyWeapons base_off=%d poff=%d parray=%p -> %d",
134 (int)base_off, poff, (void *)parray, off);
135 }
136 } else if (strcmp(pname2, "m_iAmmo") == 0 && g_net.ammo < 0) {
137 int off = (int)(base_off + (uint32_t)poff);
138 if (parray) {
139 int32_t eoff = *(int32_t *)(parray + 0x2C);
140 if (eoff)
141 off = (int)(base_off + (uint32_t)eoff);
142 }
143 if (off >= 0x20 && off <= 0x2000) {
144 g_net.ammo = off;
145 logd("netvar: m_iAmmo base_off=%d poff=%d parray=%p -> %d",
146 (int)base_off, poff, (void *)parray, off);
147 }
148 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { 178 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) {
149 g_net.teamnum = (int)(base_off + (uint32_t)poff); 179 g_net.teamnum = (int)(base_off + (uint32_t)poff);
150 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { 180 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) {