From 1dd3a4d504e98b8d18f236cb1df1fea366ddc36e Mon Sep 17 00:00:00 2001 From: salmonik Date: Tue, 27 Oct 2026 15:49:54 +0100 Subject: Spread control: override the server FireBullets seed for the local player The installed 2024 server ignores the client usercmd random_seed and uses its own shot seed. Force the server's CBaseEntity::FireBullets RandomSeed call for the local player only: - hook the server.so RandomSeed GOT slot (R_386_JUMP_SLOT at 0xce1348); - read the FireBullets `this` from the caller frame and compare it with the local server player base; - replace the seed with the precomputed best single/shotgun window and step it per pellet; NPC shots and everything else pass through. - client prediction still uses the same chosen usercmd seed, so both sides agree on the spread pattern. --- src/esp.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/esp.cpp') diff --git a/src/esp.cpp b/src/esp.cpp index 0117d27..ae08258 100644 --- a/src/esp.cpp +++ b/src/esp.cpp @@ -1057,6 +1057,7 @@ static bool g_spread_ready = false; static int g_spread_seed1 = 0; static int g_spread_seed8 = 0; // first pellet exact, 7 spread static int g_spread_seed12 = 0; // all 12 spread +int g_spread_pellets = 1; static void spread_compute() { using SeedFn = void (*)(int); @@ -1163,9 +1164,11 @@ bool spread_control_apply(CUserCmd *cmd, void *local_ent) { return false; bool shotgun = active_weapon_is_shotgun(local_ent); - int seed = g_spread_seed1; + int pellets = 1; if (shotgun) - seed = (cmd->buttons & IN_ATTACK2) ? g_spread_seed12 : g_spread_seed8; + pellets = (cmd->buttons & IN_ATTACK2) ? 12 : 8; + g_spread_pellets = pellets; + int seed = spread_best_seed(pellets); if (cmd->random_seed == seed) return false; cmd->random_seed = seed; @@ -1173,11 +1176,21 @@ bool spread_control_apply(CUserCmd *cmd, void *local_ent) { static int logs = 0; if (logs < 10) { logs++; - logf("spread: seed=%d (%s)", seed, shotgun ? "shotgun" : "single"); + logf("spread: seed=%d pellets=%d", seed, pellets); } return true; } +int spread_best_seed(int pellets) { + if (!g_spread_ready) + return 33; + if (pellets >= 12) + return g_spread_seed12; + if (pellets >= 8) + return g_spread_seed8; + return g_spread_seed1; +} + bool triggerbot_apply(CUserCmd *cmd) { if (!g_iface.enginetrace || !g_iface.entitylist) return false; -- cgit v1.2.3