diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-27 13:48:27 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-27 13:48:27 +0100 |
| commit | 471f022f449a18766fedb1ff0a4204a933b95b9c (patch) | |
| tree | 499fcd29f1c9f7933aade3f8ffad88b3ef10f377 /src/server.cpp | |
| parent | script: change the map for tests (diff) | |
| download | hl2h-471f022f449a18766fedb1ff0a4204a933b95b9c.tar.gz hl2h-471f022f449a18766fedb1ff0a4204a933b95b9c.zip | |
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.
Diffstat (limited to '')
| -rw-r--r-- | src/server.cpp | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/src/server.cpp b/src/server.cpp index 6feb55b..3766906 100644 --- a/src/server.cpp +++ b/src/server.cpp | |||
| @@ -31,6 +31,8 @@ int g_srv_health = -1; | |||
| 31 | int g_srv_maxhealth = -1; | 31 | int g_srv_maxhealth = -1; |
| 32 | int g_srv_lifestate = -1; | 32 | int g_srv_lifestate = -1; |
| 33 | int g_srv_modelindex = -1; | 33 | int g_srv_modelindex = -1; |
| 34 | int g_srv_absvelocity = -1; | ||
| 35 | int g_srv_velocity = -1; | ||
| 34 | static bool g_srv_ready = false; | 36 | static bool g_srv_ready = false; |
| 35 | static bool g_srv_checked = false; | 37 | static bool g_srv_checked = false; |
| 36 | 38 | ||
| @@ -105,12 +107,14 @@ bool resolve_server_netvars() { | |||
| 105 | g_srv_maxhealth = datamap_offset("m_iMaxHealth", FIELD_INTEGER); | 107 | g_srv_maxhealth = datamap_offset("m_iMaxHealth", FIELD_INTEGER); |
| 106 | g_srv_lifestate = datamap_offset("m_lifeState", FIELD_CHARACTER); | 108 | g_srv_lifestate = datamap_offset("m_lifeState", FIELD_CHARACTER); |
| 107 | g_srv_modelindex = datamap_offset("m_nModelIndex", 7); // FIELD_SHORT | 109 | g_srv_modelindex = datamap_offset("m_nModelIndex", 7); // FIELD_SHORT |
| 110 | g_srv_absvelocity = datamap_offset("m_vecAbsVelocity", 3); // FIELD_VECTOR | ||
| 111 | g_srv_velocity = datamap_offset("m_vecVelocity", 3); // FIELD_VECTOR | ||
| 108 | g_srv_ready = g_srv_health > 0; | 112 | g_srv_ready = g_srv_health > 0; |
| 109 | if (g_srv_ready) { | 113 | if (g_srv_ready) { |
| 110 | logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d " | 114 | logf("server datamap (%s): health=%d maxhealth=%d lifeste=%d " |
| 111 | "modelindex=%d", | 115 | "modelindex=%d absvel=%d vel=%d", |
| 112 | g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, | 116 | g_server.path.c_str(), g_srv_health, g_srv_maxhealth, g_srv_lifestate, |
| 113 | g_srv_modelindex); | 117 | g_srv_modelindex, g_srv_absvelocity, g_srv_velocity); |
| 114 | fail_logged = false; | 118 | fail_logged = false; |
| 115 | } else if (!fail_logged) { | 119 | } else if (!fail_logged) { |
| 116 | fail_logged = true; | 120 | fail_logged = true; |
| @@ -175,3 +179,18 @@ int server_model_index(void *base) { | |||
| 175 | return -1; | 179 | return -1; |
| 176 | return (int)*(short *)((uintptr_t)base + g_srv_modelindex); | 180 | return (int)*(short *)((uintptr_t)base + g_srv_modelindex); |
| 177 | } | 181 | } |
| 182 | |||
| 183 | // Set the authoritative vertical velocity of a server entity. m_vecAbsVelocity | ||
| 184 | // is what CGameMovement::SetupMove reads through GetAbsVelocity(); writing the | ||
| 185 | // networked m_vecVelocity directly is deliberately avoided because the server | ||
| 186 | // datamap scan can find a same-named field on another class first. The movement | ||
| 187 | // code syncs m_vecVelocity through SetAbsVelocity after the command. | ||
| 188 | bool server_set_velocity_z(int idx, float vz) { | ||
| 189 | if (!g_srv_ready || !g_iface.engineserver || g_srv_absvelocity <= 0) | ||
| 190 | return false; | ||
| 191 | void *base = nullptr; | ||
| 192 | if (server_entity_health(idx, nullptr, nullptr, &base) < 0 || !base) | ||
| 193 | return false; | ||
| 194 | *(float *)((uintptr_t)base + g_srv_absvelocity + 8) = vz; | ||
| 195 | return true; | ||
| 196 | } | ||
