From a029f2e25586533eb3feebab64864a69919f93b9 Mon Sep 17 00:00:00 2001 From: salmonik Date: Tue, 27 Oct 2026 15:40:52 +0100 Subject: Spread control: add server RandomSeed GOT diagnostic/override --- src/hl2h.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'src/hl2h.cpp') diff --git a/src/hl2h.cpp b/src/hl2h.cpp index ee2e990..90e0990 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp @@ -2,6 +2,8 @@ #include "hl2h.h" #include #include +#include +#include // --------------------------------------------------------------------------- // logging @@ -403,7 +405,66 @@ static bool jumpbug_apply(CUserCmd *cmd, int local, void *ent, int flags, return cmd->buttons != before; } +// --------------------------------------------------------------------------- +// server RandomSeed diagnostic / override +// --------------------------------------------------------------------------- +// +// The installed 2024 server build is stripped and its usercmd/server-random-seed +// handling differs from the 2013 SDK source. This hook is installed on the +// server.so GOT slot for RandomSeed (R_386_JUMP_SLOT at vaddr 0xce1348) so we +// can see which seed FireBullets actually uses and optionally force the chosen +// spread seed. Disabled unless HL2H_SEED_TRACE / HL2H_SEED_FORCE are set. + +static void (*g_real_random_seed)(int) = nullptr; +static uintptr_t g_srv_base = 0; +static bool g_seed_hook_installed = false; + +static void hkdSrvRandomSeed(int seed) { + uintptr_t ret = (uintptr_t)__builtin_return_address(0); + long off = (long)(ret - g_srv_base); + static bool trace = getenv("HL2H_SEED_TRACE") != nullptr; + static bool force = getenv("HL2H_SEED_FORCE") != nullptr; + static int logs = 0; + bool bullet_site = (off >= 0x216900 && off <= 0x216930); + if (trace && (bullet_site || logs < 12)) { + if (logs < 200) { + logs++; + logf("srvseed: seed=%d off=0x%lx bullet=%d", seed, off, + (int)bullet_site); + } + } + if (force && bullet_site) + seed = 33; + if (g_real_random_seed) + g_real_random_seed(seed); +} + +static void install_seed_hook() { + if (g_seed_hook_installed || !g_server.valid()) + return; + g_srv_base = g_server.ranges[0].lo; + uintptr_t slot = g_srv_base + 0xce1348; // R_386_JUMP_SLOT RandomSeed + if (!g_server.contains(slot)) + return; + g_real_random_seed = + (void (*)(int))dlsym(RTLD_NEXT, "RandomSeed"); + if (!g_real_random_seed) + g_real_random_seed = (void (*)(int))dlsym(RTLD_DEFAULT, "RandomSeed"); + if (!g_real_random_seed) { + logf("seed hook: real RandomSeed not found"); + return; + } + mprotect((void *)(slot & ~(uintptr_t)0xFFF), 0x1000, + PROT_READ | PROT_WRITE | PROT_EXEC); + *(uint32_t *)slot = (uint32_t)(uintptr_t)&hkdSrvRandomSeed; + g_seed_hook_installed = true; + logf("seed hook: server GOT %#lx -> %p (real %p)", + (unsigned long)slot, (void *)&hkdSrvRandomSeed, + (void *)g_real_random_seed); +} + static void do_move(int seq, float frametime) { + install_seed_hook(); static bool g_echo_sent = false; if (!g_input || !g_net.ok()) return; -- cgit v1.2.3