From 471f022f449a18766fedb1ff0a4204a933b95b9c Mon Sep 17 00:00:00 2001 From: salmonik Date: Tue, 27 Oct 2026 13:48:27 +0100 Subject: Jumpbug: optional velocity-timed assist The unduck window is only 2 units, while a 625-ups fall moves ~9.3 units per 66.7 Hz movement command, so pure jumpbug is ~20% reliable at that speed. - Add Jumpbug -> Assist timing (default off). When the natural next command would skip [36,38], pin the post-command ducked distance to 37 by writing the vertical velocity for that command. Pure jumpbug remains available with the option off. - Resolve the client local m_vecAbsVelocity (0x11C) via the client datamap and the server m_vecAbsVelocity (0x228) via the server datamap. - Write both the authoritative server velocity (what SetupMove reads through GetAbsVelocity) and the local prediction fields, so the next CreateMove sees the assisted origin on both sides. - Do not write the server m_vecVelocity directly: the datamap scan finds two same-named entries (0x1C and 0x29C); SetAbsVelocity syncs it after movement. --- src/netvars.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) (limited to 'src/netvars.cpp') diff --git a/src/netvars.cpp b/src/netvars.cpp index b4e31d5..98ebe31 100644 --- a/src/netvars.cpp +++ b/src/netvars.cpp @@ -185,6 +185,66 @@ static bool resolve_movetype() { return true; } +static bool resolve_absvelocity() { + static const char needle[] = "m_vecAbsVelocity"; + const size_t nlen = sizeof(needle); + + uintptr_t str_va = 0; + for (auto &r : g_client.ranges) { + const uint8_t *base = (const uint8_t *)r.lo; + size_t span = r.hi - r.lo; + for (size_t i = 0; i + nlen <= span; i++) { + if (memcmp(base + i, needle, nlen) == 0) { + str_va = r.lo + i; + break; + } + } + if (str_va) + break; + } + if (!str_va) { + logf("m_vecAbsVelocity string not found"); + return false; + } + + uint32_t offs[16]; + int counts[16] = {}; + int ncand = 0; + const uint32_t target = (uint32_t)str_va; + for (auto &r : g_client.ranges) { + const uint8_t *base = (const uint8_t *)r.lo; + size_t span = r.hi - r.lo; + for (size_t off = 4; off + 8 <= span; off += 4) { + if (*(const uint32_t *)(base + off) != target) + continue; + uint32_t ftype = *(const uint32_t *)(base + off - 4); + int32_t foff = *(const int32_t *)(base + off + 4); + if (ftype != 3 || foff < 0x40 || foff > 0x400) + continue; + int k; + for (k = 0; k < ncand; k++) + if (offs[k] == (uint32_t)foff) + break; + if (k == ncand && ncand < 16) { + offs[ncand] = (uint32_t)foff; + ncand++; + } + if (k < ncand) + counts[k]++; + } + } + if (ncand == 0) { + logf("m_vecAbsVelocity typedescription not found"); + return false; + } + int best = 0; + for (int k = 1; k < ncand; k++) + if (counts[k] > counts[best]) + best = k; + g_net.absvelocity = (int)offs[best]; + return true; +} + void resolve_netvars() { using GetAllClassesFn = void *(*)(void *); uintptr_t head = @@ -205,10 +265,13 @@ void resolve_netvars() { // movetype unresolved — bhop still works, just no noclip/ladder guard logf("movetype guard disabled"); } + if (g_net.absvelocity < 0 && !resolve_absvelocity()) + logf("m_vecAbsVelocity unresolved; jumpbug assist disabled"); logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d " "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d " - "modelindex=%d", + "modelindex=%d absvelocity=%d", g_net.flags, g_net.velocity, g_net.movetype, g_net.health, g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset, - g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex); + g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex, + g_net.absvelocity); } -- cgit v1.2.3