From 12fde50efc7e1f1d123f9fc34ffef53d4387de2d Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Nov 2026 13:53:45 +0100 Subject: 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. --- src/server.cpp | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 3 deletions(-) (limited to 'src/server.cpp') 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; static int g_srv_hacked = -1; static int g_srv_npcstate = -1; static int g_srv_takedamage = -1; +static int g_srv_mapname = -1; static bool g_srv_ready = false; static bool g_srv_checked = false; @@ -91,7 +92,7 @@ static int datamap_offset(const char *name, int want_type, int min_off = 0x40, continue; if (foff < min_off || foff > max_off) continue; - if (fsize < 1 || fsize > 64) + if (fsize < 1 || fsize > 128) continue; // DEFINE_KEYFIELD entries have an external name ("health"); plain // DEFINE_FIELD entries have none. Either way it must be in server.so. @@ -147,16 +148,19 @@ bool resolve_server_netvars() { g_srv_takedamage = datamap_offset("m_takedamage", FIELD_CHARACTER); if (g_srv_takedamage < 0) g_srv_takedamage = datamap_offset("m_takedamage", FIELD_INTEGER); + // CChangeLevel::m_szMapName is a char[cchMapNameMost] on trigger_changelevel. + g_srv_mapname = datamap_offset("m_szMapName", FIELD_CHARACTER, 0x40, 0x4000); g_srv_ready = g_srv_health > 0; if (g_srv_ready) { logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d " "modelindex=%d absvel=%d vel=%d activeweapon=%d relationship=%d " "followtarget=%d spawnflags=%d hacked=%d npcstate=%d " - "takedamage=%d", + "takedamage=%d mapname=%d", g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, g_srv_modelindex, g_srv_absvelocity, g_srv_velocity, g_srv_activeweapon, g_srv_relationship, g_srv_followtarget, - g_srv_spawnflags, g_srv_hacked, g_srv_npcstate, g_srv_takedamage); + g_srv_spawnflags, g_srv_hacked, g_srv_npcstate, g_srv_takedamage, + g_srv_mapname); fail_logged = false; } else if (!fail_logged) { fail_logged = true; @@ -223,6 +227,92 @@ int server_model_index(void *base) { return (int)*(short *)((uintptr_t)base + g_srv_modelindex); } +int server_entity_count() { + if (!g_iface.engineserver) + return 0; + using CountFn = int (*)(void *); + int n = vfunc(g_iface.engineserver, SRV_GetEntityCount)( + g_iface.engineserver); + return (n > 0 && n <= 8192) ? n : 0; +} + +static void *edict_unknown(int idx) { + if (!g_iface.engineserver) + return nullptr; + using PEntityFn = void *(*)(void *, int); + void *edict = vfunc(g_iface.engineserver, SRV_PEntityOfEntIndex)( + g_iface.engineserver, idx); + if (!edict) + return nullptr; + return *(void **)((uintptr_t)edict + EDICT_UNKNOWN_OFF); +} + +void *server_entity_base(int idx) { + void *unk = edict_unknown(idx); + if (!unk) + return nullptr; + using GetBaseFn = void *(*)(void *); + return vfunc(unk, SRV_GetBaseEntity)(unk); +} + +// Linked entity class name (e.g. "weapon_smg1", "trigger_changelevel"). +const char *server_entity_classname(int idx) { + void *unk = edict_unknown(idx); + if (!unk) + return nullptr; + using GetNetFn = void *(*)(void *); + void *net = vfunc(unk, 5)(unk); + if (!net) + return nullptr; + using NameFn = const char *(*)(void *); + return vfunc(net, 3)(net); +} + +// A trigger_changelevel's target map and world-space brush bounds. The class +// name comes from IServerNetworkable::GetClassName (slot 3); the volume from +// ICollideable::WorldSpaceSurroundingBounds (slot 17, no virtual dtor). +bool server_trigger_info(int idx, char *map, size_t mapn, Vector &mins, + Vector &maxs) { + if (!g_srv_ready || g_srv_mapname < 0) + return false; + void *unk = edict_unknown(idx); + if (!unk) + return false; + using GetNetFn = void *(*)(void *); + void *net = vfunc(unk, 5)(unk); + if (!net) + return false; + using NameFn = const char *(*)(void *); + const char *cls = vfunc(net, 3)(net); + if (!cls || !strcasestr(cls, "changelevel")) + return false; + void *base = server_entity_base(idx); + if (!base) + return false; + const char *m = (const char *)((uintptr_t)base + g_srv_mapname); + size_t n = strnlen(m, 32); // cchMapNameMost + if (n == 0 || n >= 32) + return false; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)m[i]; + if (c < 0x20 || c > 0x7e) + return false; + } + if (map && mapn) { + if (n >= mapn) + n = mapn - 1; + memcpy(map, m, n); + map[n] = 0; + } + using GetCollFn = void *(*)(void *); + void *coll = vfunc(unk, 4)(unk); + if (coll) { + using BoundsFn = void (*)(void *, Vector *, Vector *); + vfunc(coll, 17)(coll, &mins, &maxs); + } + return true; +} + // Set the authoritative vertical velocity of a server entity. m_vecAbsVelocity // is what CGameMovement::SetupMove reads through GetAbsVelocity(); writing the // networked m_vecVelocity directly is deliberately avoided because the server -- cgit v1.2.3