summaryrefslogtreecommitdiffstats
path: root/src/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.cpp')
-rw-r--r--src/server.cpp64
1 files changed, 60 insertions, 4 deletions
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;