diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-04 13:53:45 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-04 13:53:45 +0100 |
| commit | 12fde50efc7e1f1d123f9fc34ffef53d4387de2d (patch) | |
| tree | 4de53807ce23df9b63598a0e3a12620ff19eb7cc /src/server.cpp | |
| parent | No spread: detect pellet draws from the FireBullets seed call (diff) | |
| download | hl2h-12fde50efc7e1f1d123f9fc34ffef53d4387de2d.tar.gz hl2h-12fde50efc7e1f1d123f9fc34ffef53d4387de2d.zip | |
Add ESP, aim, view and movement batch
- ESP: alert state (IDLE/ALERT/COMBAT/SCRIPT), enemy weapon labels, hostile/
neutral/friendly colour pickers, off-screen direction arrows, and
trigger_changelevel volumes with next/previous map labels.
- Aim: silent aim reuses the Aimbot FOV, vischeck and bone settings; add
optional aim-punch compensation for aimbot, silent aim, triggerbot and
melee (server bullets add m_vecPunchAngle to the usercmd angles).
- View: always-on Camera / display card with camera FOV (writes the client
m_iDefaultFOV netvar), viewmodel FOV and monitor gamma (client cvars).
- Movement: Jump assist card with auto crouch-jump and edge jump (point
ground probe 0.12 s ahead).
- Spread: Engine spread override toggle gates the direct RandomFloat zeroing;
off leaves only the seed search.
- Server: entity count/base/classname helpers, trigger_changelevel map name
and world bounds via IServerUnknown/ICollideable.
- Netvars: m_vecPunchAngle and m_iDefaultFOV.
Diffstat (limited to 'src/server.cpp')
| -rw-r--r-- | src/server.cpp | 96 |
1 files changed, 93 insertions, 3 deletions
diff --git a/src/server.cpp b/src/server.cpp index f71b441..39bb162 100644 --- a/src/server.cpp +++ b/src/server.cpp | |||
| @@ -52,6 +52,7 @@ static int g_srv_spawnflags = -1; | |||
| 52 | static int g_srv_hacked = -1; | 52 | static int g_srv_hacked = -1; |
| 53 | static int g_srv_npcstate = -1; | 53 | static int g_srv_npcstate = -1; |
| 54 | static int g_srv_takedamage = -1; | 54 | static int g_srv_takedamage = -1; |
| 55 | static int g_srv_mapname = -1; | ||
| 55 | static bool g_srv_ready = false; | 56 | static bool g_srv_ready = false; |
| 56 | static bool g_srv_checked = false; | 57 | static bool g_srv_checked = false; |
| 57 | 58 | ||
| @@ -91,7 +92,7 @@ static int datamap_offset(const char *name, int want_type, int min_off = 0x40, | |||
| 91 | continue; | 92 | continue; |
| 92 | if (foff < min_off || foff > max_off) | 93 | if (foff < min_off || foff > max_off) |
| 93 | continue; | 94 | continue; |
| 94 | if (fsize < 1 || fsize > 64) | 95 | if (fsize < 1 || fsize > 128) |
| 95 | continue; | 96 | continue; |
| 96 | // DEFINE_KEYFIELD entries have an external name ("health"); plain | 97 | // DEFINE_KEYFIELD entries have an external name ("health"); plain |
| 97 | // DEFINE_FIELD entries have none. Either way it must be in server.so. | 98 | // DEFINE_FIELD entries have none. Either way it must be in server.so. |
| @@ -147,16 +148,19 @@ bool resolve_server_netvars() { | |||
| 147 | g_srv_takedamage = datamap_offset("m_takedamage", FIELD_CHARACTER); | 148 | g_srv_takedamage = datamap_offset("m_takedamage", FIELD_CHARACTER); |
| 148 | if (g_srv_takedamage < 0) | 149 | if (g_srv_takedamage < 0) |
| 149 | g_srv_takedamage = datamap_offset("m_takedamage", FIELD_INTEGER); | 150 | g_srv_takedamage = datamap_offset("m_takedamage", FIELD_INTEGER); |
| 151 | // CChangeLevel::m_szMapName is a char[cchMapNameMost] on trigger_changelevel. | ||
| 152 | g_srv_mapname = datamap_offset("m_szMapName", FIELD_CHARACTER, 0x40, 0x4000); | ||
| 150 | g_srv_ready = g_srv_health > 0; | 153 | g_srv_ready = g_srv_health > 0; |
| 151 | if (g_srv_ready) { | 154 | if (g_srv_ready) { |
| 152 | logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d " | 155 | logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d " |
| 153 | "modelindex=%d absvel=%d vel=%d activeweapon=%d relationship=%d " | 156 | "modelindex=%d absvel=%d vel=%d activeweapon=%d relationship=%d " |
| 154 | "followtarget=%d spawnflags=%d hacked=%d npcstate=%d " | 157 | "followtarget=%d spawnflags=%d hacked=%d npcstate=%d " |
| 155 | "takedamage=%d", | 158 | "takedamage=%d mapname=%d", |
| 156 | g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, | 159 | g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, |
| 157 | g_srv_modelindex, g_srv_absvelocity, g_srv_velocity, | 160 | g_srv_modelindex, g_srv_absvelocity, g_srv_velocity, |
| 158 | g_srv_activeweapon, g_srv_relationship, g_srv_followtarget, | 161 | g_srv_activeweapon, g_srv_relationship, g_srv_followtarget, |
| 159 | g_srv_spawnflags, g_srv_hacked, g_srv_npcstate, g_srv_takedamage); | 162 | g_srv_spawnflags, g_srv_hacked, g_srv_npcstate, g_srv_takedamage, |
| 163 | g_srv_mapname); | ||
| 160 | fail_logged = false; | 164 | fail_logged = false; |
| 161 | } else if (!fail_logged) { | 165 | } else if (!fail_logged) { |
| 162 | fail_logged = true; | 166 | fail_logged = true; |
| @@ -223,6 +227,92 @@ int server_model_index(void *base) { | |||
| 223 | return (int)*(short *)((uintptr_t)base + g_srv_modelindex); | 227 | return (int)*(short *)((uintptr_t)base + g_srv_modelindex); |
| 224 | } | 228 | } |
| 225 | 229 | ||
| 230 | int server_entity_count() { | ||
| 231 | if (!g_iface.engineserver) | ||
| 232 | return 0; | ||
| 233 | using CountFn = int (*)(void *); | ||
| 234 | int n = vfunc<CountFn>(g_iface.engineserver, SRV_GetEntityCount)( | ||
| 235 | g_iface.engineserver); | ||
| 236 | return (n > 0 && n <= 8192) ? n : 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | static void *edict_unknown(int idx) { | ||
| 240 | if (!g_iface.engineserver) | ||
| 241 | return nullptr; | ||
| 242 | using PEntityFn = void *(*)(void *, int); | ||
| 243 | void *edict = vfunc<PEntityFn>(g_iface.engineserver, SRV_PEntityOfEntIndex)( | ||
| 244 | g_iface.engineserver, idx); | ||
| 245 | if (!edict) | ||
| 246 | return nullptr; | ||
| 247 | return *(void **)((uintptr_t)edict + EDICT_UNKNOWN_OFF); | ||
| 248 | } | ||
| 249 | |||
| 250 | void *server_entity_base(int idx) { | ||
| 251 | void *unk = edict_unknown(idx); | ||
| 252 | if (!unk) | ||
| 253 | return nullptr; | ||
| 254 | using GetBaseFn = void *(*)(void *); | ||
| 255 | return vfunc<GetBaseFn>(unk, SRV_GetBaseEntity)(unk); | ||
| 256 | } | ||
| 257 | |||
| 258 | // Linked entity class name (e.g. "weapon_smg1", "trigger_changelevel"). | ||
| 259 | const char *server_entity_classname(int idx) { | ||
| 260 | void *unk = edict_unknown(idx); | ||
| 261 | if (!unk) | ||
| 262 | return nullptr; | ||
| 263 | using GetNetFn = void *(*)(void *); | ||
| 264 | void *net = vfunc<GetNetFn>(unk, 5)(unk); | ||
| 265 | if (!net) | ||
| 266 | return nullptr; | ||
| 267 | using NameFn = const char *(*)(void *); | ||
| 268 | return vfunc<NameFn>(net, 3)(net); | ||
| 269 | } | ||
| 270 | |||
| 271 | // A trigger_changelevel's target map and world-space brush bounds. The class | ||
| 272 | // name comes from IServerNetworkable::GetClassName (slot 3); the volume from | ||
| 273 | // ICollideable::WorldSpaceSurroundingBounds (slot 17, no virtual dtor). | ||
| 274 | bool server_trigger_info(int idx, char *map, size_t mapn, Vector &mins, | ||
| 275 | Vector &maxs) { | ||
| 276 | if (!g_srv_ready || g_srv_mapname < 0) | ||
| 277 | return false; | ||
| 278 | void *unk = edict_unknown(idx); | ||
| 279 | if (!unk) | ||
| 280 | return false; | ||
| 281 | using GetNetFn = void *(*)(void *); | ||
| 282 | void *net = vfunc<GetNetFn>(unk, 5)(unk); | ||
| 283 | if (!net) | ||
| 284 | return false; | ||
| 285 | using NameFn = const char *(*)(void *); | ||
| 286 | const char *cls = vfunc<NameFn>(net, 3)(net); | ||
| 287 | if (!cls || !strcasestr(cls, "changelevel")) | ||
| 288 | return false; | ||
| 289 | void *base = server_entity_base(idx); | ||
| 290 | if (!base) | ||
| 291 | return false; | ||
| 292 | const char *m = (const char *)((uintptr_t)base + g_srv_mapname); | ||
| 293 | size_t n = strnlen(m, 32); // cchMapNameMost | ||
| 294 | if (n == 0 || n >= 32) | ||
| 295 | return false; | ||
| 296 | for (size_t i = 0; i < n; i++) { | ||
| 297 | unsigned char c = (unsigned char)m[i]; | ||
| 298 | if (c < 0x20 || c > 0x7e) | ||
| 299 | return false; | ||
| 300 | } | ||
| 301 | if (map && mapn) { | ||
| 302 | if (n >= mapn) | ||
| 303 | n = mapn - 1; | ||
| 304 | memcpy(map, m, n); | ||
| 305 | map[n] = 0; | ||
| 306 | } | ||
| 307 | using GetCollFn = void *(*)(void *); | ||
| 308 | void *coll = vfunc<GetCollFn>(unk, 4)(unk); | ||
| 309 | if (coll) { | ||
| 310 | using BoundsFn = void (*)(void *, Vector *, Vector *); | ||
| 311 | vfunc<BoundsFn>(coll, 17)(coll, &mins, &maxs); | ||
| 312 | } | ||
| 313 | return true; | ||
| 314 | } | ||
| 315 | |||
| 226 | // Set the authoritative vertical velocity of a server entity. m_vecAbsVelocity | 316 | // Set the authoritative vertical velocity of a server entity. m_vecAbsVelocity |
| 227 | // is what CGameMovement::SetupMove reads through GetAbsVelocity(); writing the | 317 | // is what CGameMovement::SetupMove reads through GetAbsVelocity(); writing the |
| 228 | // networked m_vecVelocity directly is deliberately avoided because the server | 318 | // networked m_vecVelocity directly is deliberately avoided because the server |
