summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/esp.cpp45
-rw-r--r--src/hl2h.h2
-rw-r--r--src/server.cpp64
3 files changed, 101 insertions, 10 deletions
diff --git a/src/esp.cpp b/src/esp.cpp
index 7c3f1bc..0966ff5 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -148,6 +148,34 @@ static bool model_is_neutral(const char *m) {
148 return false; 148 return false;
149} 149}
150 150
151static bool npc_is_friendly(int idx, const char *model, int local_idx,
152 bool &neutral) {
153 int rel = server_npc_relation(idx, local_idx);
154 if (rel == 3) { // D_LI
155 neutral = false;
156 return true;
157 }
158 if (rel == 4) { // D_NU
159 neutral = true;
160 return false;
161 }
162 if (rel == 1 || rel == 2) { // D_HT / D_FR
163 neutral = false;
164 return false;
165 }
166 // Bugbait-controlled antlions follow a target even when their default
167 // relationship was never rewritten.
168 if (model && strstr(model, "antlion") &&
169 server_npc_has_follow_target(idx)) {
170 neutral = false;
171 return true;
172 }
173 bool friendly = model_is_friendly(model);
174 neutral = model_is_neutral(model);
175 return friendly;
176}
177
178
151static void short_name(const char *model, char *out, size_t outn) { 179static void short_name(const char *model, char *out, size_t outn) {
152 if (!model) { snprintf(out, outn, "NPC"); return; } 180 if (!model) { snprintf(out, outn, "NPC"); return; }
153 const char *base = strrchr(model, '/'); 181 const char *base = strrchr(model, '/');
@@ -259,8 +287,9 @@ static void esp_collect(int local_idx) {
259 t.health = hp > 0 ? (float)hp : 0.0f; 287 t.health = hp > 0 ? (float)hp : 0.0f;
260 t.maxhealth = maxhp > 0 ? (float)maxhp : 100.0f; 288 t.maxhealth = maxhp > 0 ? (float)maxhp : 100.0f;
261 t.show_health = hp > 0; 289 t.show_health = hp > 0;
262 t.friendly = model_is_friendly(model); 290 bool neutral = false;
263 t.neutral = model_is_neutral(model); 291 t.friendly = npc_is_friendly(idx, model, local_idx, neutral);
292 t.neutral = neutral;
264 short_name(model, t.name, sizeof(t.name)); 293 short_name(model, t.name, sizeof(t.name));
265 if (npc && !model) snprintf(t.name, sizeof(t.name), "NPC"); 294 if (npc && !model) snprintf(t.name, sizeof(t.name), "NPC");
266 } 295 }
@@ -527,7 +556,8 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask,
527 if (life != LIFE_ALIVE) 556 if (life != LIFE_ALIVE)
528 return false; 557 return false;
529 const char *model = entity_model_name(ent); 558 const char *model = entity_model_name(ent);
530 if (model_is_friendly(model) || model_is_neutral(model)) 559 bool neutral = false;
560 if (npc_is_friendly(idx, model, local, neutral) || neutral)
531 return false; 561 return false;
532 if (!bones_update(idx, ent)) 562 if (!bones_update(idx, ent))
533 return false; 563 return false;
@@ -605,7 +635,8 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask,
605 if (life != LIFE_ALIVE) 635 if (life != LIFE_ALIVE)
606 continue; 636 continue;
607 const char *model = entity_model_name(ent); 637 const char *model = entity_model_name(ent);
608 if (model_is_friendly(model) || model_is_neutral(model)) 638 bool neutral = false;
639 if (npc_is_friendly(idx, model, local, neutral) || neutral)
609 continue; 640 continue;
610 641
611 float maxz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs + 8) : 72.0f; 642 float maxz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs + 8) : 72.0f;
@@ -990,7 +1021,8 @@ bool melee_aimbot_apply(CUserCmd *cmd) {
990 if (life != LIFE_ALIVE) 1021 if (life != LIFE_ALIVE)
991 continue; 1022 continue;
992 const char *model = entity_model_name(ent); 1023 const char *model = entity_model_name(ent);
993 if (model_is_friendly(model) || model_is_neutral(model)) 1024 bool neutral = false;
1025 if (npc_is_friendly(idx, model, local, neutral) || neutral)
994 continue; 1026 continue;
995 1027
996 Vector origin{*(float *)(e + g_net.origin), 1028 Vector origin{*(float *)(e + g_net.origin),
@@ -1320,7 +1352,8 @@ bool triggerbot_apply(CUserCmd *cmd) {
1320 if (life != LIFE_ALIVE) 1352 if (life != LIFE_ALIVE)
1321 return false; 1353 return false;
1322 const char *model = entity_model_name(hit); 1354 const char *model = entity_model_name(hit);
1323 if (model_is_friendly(model) || model_is_neutral(model)) 1355 bool neutral = false;
1356 if (npc_is_friendly(idx, model, local, neutral) || neutral)
1324 return false; 1357 return false;
1325 cmd->buttons |= IN_ATTACK; 1358 cmd->buttons |= IN_ATTACK;
1326 static int logs = 0; 1359 static int logs = 0;
diff --git a/src/hl2h.h b/src/hl2h.h
index e441167..414e061 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -252,6 +252,8 @@ bool resolve_server_netvars();
252int server_entity_health(int idx, int *maxhealth, int *lifestate, void **base_out); 252int server_entity_health(int idx, int *maxhealth, int *lifestate, void **base_out);
253bool server_set_velocity_z(int idx, float vz); 253bool server_set_velocity_z(int idx, float vz);
254int server_active_weapon(int idx); 254int server_active_weapon(int idx);
255int server_npc_relation(int idx, int local_idx);
256bool server_npc_has_follow_target(int idx);
255int server_model_index(void *base); 257int server_model_index(void *base);
256void find_modules(); 258void find_modules();
257void init_conmsg(); 259void init_conmsg();
diff --git a/src/server.cpp b/src/server.cpp
index 5599227..4702c44 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -25,7 +25,12 @@ enum { EDICT_UNKNOWN_OFF = 0x0C };
25 25
26// typedescription_t (32-bit): fieldType@0, fieldName@4, fieldOffset[0]@8, 26// typedescription_t (32-bit): fieldType@0, fieldName@4, fieldOffset[0]@8,
27// fieldOffset[1]@0xC, fieldSize@0x10, flags@0x12, externalName@0x14 27// fieldOffset[1]@0xC, fieldSize@0x10, flags@0x12, externalName@0x14
28enum { FIELD_INTEGER = 5, FIELD_CHARACTER = 8 }; 28enum {
29 FIELD_INTEGER = 5,
30 FIELD_CHARACTER = 8,
31 FIELD_EMBEDDED = 10,
32 FIELD_EHANDLE = 13
33};
29 34
30int g_srv_health = -1; 35int g_srv_health = -1;
31int g_srv_maxhealth = -1; 36int g_srv_maxhealth = -1;
@@ -34,6 +39,8 @@ int g_srv_modelindex = -1;
34int g_srv_absvelocity = -1; 39int g_srv_absvelocity = -1;
35int g_srv_velocity = -1; 40int g_srv_velocity = -1;
36int g_srv_activeweapon = -1; 41int g_srv_activeweapon = -1;
42static int g_srv_relationship = -1;
43static int g_srv_followtarget = -1;
37static bool g_srv_ready = false; 44static bool g_srv_ready = false;
38static bool g_srv_checked = false; 45static bool g_srv_checked = false;
39 46
@@ -110,14 +117,17 @@ bool resolve_server_netvars() {
110 g_srv_modelindex = datamap_offset("m_nModelIndex", 7); // FIELD_SHORT 117 g_srv_modelindex = datamap_offset("m_nModelIndex", 7); // FIELD_SHORT
111 g_srv_absvelocity = datamap_offset("m_vecAbsVelocity", 3); // FIELD_VECTOR 118 g_srv_absvelocity = datamap_offset("m_vecAbsVelocity", 3); // FIELD_VECTOR
112 g_srv_velocity = datamap_offset("m_vecVelocity", 3); // FIELD_VECTOR 119 g_srv_velocity = datamap_offset("m_vecVelocity", 3); // FIELD_VECTOR
113 g_srv_activeweapon = datamap_offset("m_hActiveWeapon", 13); // FIELD_EHANDLE 120 g_srv_activeweapon = datamap_offset("m_hActiveWeapon", FIELD_EHANDLE);
121 g_srv_relationship = datamap_offset("m_Relationship", FIELD_EMBEDDED);
122 g_srv_followtarget = datamap_offset("m_hFollowTarget", FIELD_EHANDLE);
114 g_srv_ready = g_srv_health > 0; 123 g_srv_ready = g_srv_health > 0;
115 if (g_srv_ready) { 124 if (g_srv_ready) {
116 logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d " 125 logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d "
117 "modelindex=%d absvel=%d vel=%d activeweapon=%d", 126 "modelindex=%d absvel=%d vel=%d activeweapon=%d relationship=%d "
127 "followtarget=%d",
118 g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, 128 g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate,
119 g_srv_modelindex, g_srv_absvelocity, g_srv_velocity, 129 g_srv_modelindex, g_srv_absvelocity, g_srv_velocity,
120 g_srv_activeweapon); 130 g_srv_activeweapon, g_srv_relationship, g_srv_followtarget);
121 fail_logged = false; 131 fail_logged = false;
122 } else if (!fail_logged) { 132 } else if (!fail_logged) {
123 fail_logged = true; 133 fail_logged = true;
@@ -189,6 +199,52 @@ int server_model_index(void *base) {
189// networked m_vecVelocity directly is deliberately avoided because the server 199// networked m_vecVelocity directly is deliberately avoided because the server
190// datamap scan can find a same-named field on another class first. The movement 200// datamap scan can find a same-named field on another class first. The movement
191// code syncs m_vecVelocity through SetAbsVelocity after the command. 201// code syncs m_vecVelocity through SetAbsVelocity after the command.
202// Server-side AI relationship (D_ER=0, D_HT=1, D_FR=2, D_LI=3, D_NU=4).
203// m_Relationship is a CUtlVector<Relationship_t>; each entry is
204// EHANDLE entity, Class_T classType, Disposition_t disposition, int priority.
205int server_npc_relation(int idx, int local_idx) {
206 if (!g_srv_ready || g_srv_relationship < 0 || local_idx <= 0)
207 return -1;
208 void *base = nullptr;
209 server_entity_health(idx, nullptr, nullptr, &base);
210 if (!base)
211 return -1;
212 uintptr_t rel = (uintptr_t)base + g_srv_relationship;
213 int count = *(int *)(rel + 12);
214 if (count <= 0 || count > 64)
215 return -1;
216 uintptr_t elems = *(uintptr_t *)(rel + 16);
217 if (!elems)
218 elems = *(uintptr_t *)(rel + 0);
219 if (!elems || (elems & 3))
220 return -1;
221 int class_relation = -1;
222 for (int i = 0; i < count; i++) {
223 uintptr_t e = elems + (uintptr_t)i * 16;
224 uint32_t h = *(uint32_t *)(e + 0);
225 int class_type = *(int *)(e + 4);
226 int disposition = *(int *)(e + 8);
227 if (h != 0 && h != 0xFFFFFFFFu) {
228 if ((int)(h & 0x7FF) == local_idx)
229 return disposition;
230 } else if (class_type == 1) { // CLASS_PLAYER
231 class_relation = disposition;
232 }
233 }
234 return class_relation;
235}
236
237bool server_npc_has_follow_target(int idx) {
238 if (!g_srv_ready || g_srv_followtarget < 0)
239 return false;
240 void *base = nullptr;
241 server_entity_health(idx, nullptr, nullptr, &base);
242 if (!base)
243 return false;
244 uint32_t h = *(uint32_t *)((uintptr_t)base + g_srv_followtarget);
245 return h != 0 && h != 0xFFFFFFFFu;
246}
247
192bool server_set_velocity_z(int idx, float vz) { 248bool server_set_velocity_z(int idx, float vz) {
193 if (!g_srv_ready || !g_iface.engineserver || g_srv_absvelocity <= 0) 249 if (!g_srv_ready || !g_iface.engineserver || g_srv_absvelocity <= 0)
194 return false; 250 return false;