summaryrefslogtreecommitdiffstats
path: root/src/cinput.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-27 15:32:26 +0100
committersalmonik <salmonik@tuta.io>2026-10-27 15:32:26 +0100
commit902507c1173a03a04fc49cfe421bc3c3fb49d8fb (patch)
tree433cae8017464b2fb8f7ed92be8d894db521be38 /src/cinput.cpp
parentSpread control: client-seed no-spread (diff)
downloadhl2h-902507c1173a03a04fc49cfe421bc3c3fb49d8fb.tar.gz
hl2h-902507c1173a03a04fc49cfe421bc3c3fb49d8fb.zip
Spread control: set random_seed after CInput::CreateMove
CInput::CreateMove overwrites cmd->random_seed with MD5_PseudoRandom after CHLClient::CreateMove returns, so the seed set from the client-mode hook was being discarded. Hook the IInput vtable slot 3 (CInput::CreateMove), call the original, then apply the spread seed and update the verified command copy and CRC. This also keeps all aim/movement edits since the original copies the command into the verified table.
Diffstat (limited to '')
-rw-r--r--src/cinput.cpp58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/cinput.cpp b/src/cinput.cpp
index f4ba322..a75cc4f 100644
--- a/src/cinput.cpp
+++ b/src/cinput.cpp
@@ -74,6 +74,63 @@ void fix_verified_crc(int seq, uint32_t crc) {
74} 74}
75 75
76// --------------------------------------------------------------------------- 76// ---------------------------------------------------------------------------
77// CInput::CreateMove hook
78// ---------------------------------------------------------------------------
79//
80// The CHLClient::CreateMove hook runs *inside* CInput::CreateMove. After it
81// returns, CInput::CreateMove overwrites cmd->random_seed with
82// MD5_PseudoRandom(sequence_number), then copies the command into the verified
83// command table. To choose the bullet-spread seed we must hook CInput itself
84// and run after that assignment.
85
86using InputCreateMoveFn = void (*)(void *, int, float, bool);
87static InputCreateMoveFn oInputCreateMove = nullptr;
88
89static void hkdInputCreateMove(void *self, int seq, float frametime,
90 bool active) {
91 if (oInputCreateMove)
92 oInputCreateMove(self, seq, frametime, active);
93
94 CUserCmd *cmd = get_usercmd(seq);
95 if (!cmd)
96 return;
97 int local = engine_get_local_player();
98 if (local <= 0)
99 return;
100 void *ent = entitylist_get(local);
101 if (!ent)
102 return;
103 if (!spread_control_apply(cmd, ent))
104 return;
105
106 // Keep the verified command copy and its CRC in sync with the modified
107 // random_seed. CInput::CreateMove already copied all other (aim/move) fields.
108 uintptr_t verified = *(uintptr_t *)(g_input + CMDOFF_M_PVERIFIED);
109 if (verified) {
110 CUserCmd *vc =
111 (CUserCmd *)(verified + (size_t)(seq % 90) * VERIFIED_STRIDE);
112 vc->random_seed = cmd->random_seed;
113 }
114 fix_verified_crc(seq, usercmd_checksum(cmd));
115}
116
117static bool install_input_hook() {
118 if (!g_input)
119 return false;
120 void **vt = VTABLE((void *)g_input);
121 if (!vt)
122 return false;
123 constexpr size_t N = 64;
124 void **nvt = new void *[N];
125 memcpy(nvt, vt, N * sizeof(void *));
126 oInputCreateMove = (InputCreateMoveFn)vt[3];
127 nvt[3] = (void *)&hkdInputCreateMove;
128 VTABLE((void *)g_input) = nvt;
129 logf("CInput CreateMove hooked: slot 3 orig=%p", (void *)oInputCreateMove);
130 return true;
131}
132
133// ---------------------------------------------------------------------------
77// CInput discovery: byte-scan of CHLClient::CreateMove prologue 134// CInput discovery: byte-scan of CHLClient::CreateMove prologue
78// --------------------------------------------------------------------------- 135// ---------------------------------------------------------------------------
79 136
@@ -135,6 +192,7 @@ bool find_input_global() {
135 logf("CInput* = %#lx (ptr var %#lx, vfunc[3] %#lx)", (unsigned long)input, 192 logf("CInput* = %#lx (ptr var %#lx, vfunc[3] %#lx)", (unsigned long)input,
136 (unsigned long)var, (unsigned long)f3); 193 (unsigned long)var, (unsigned long)f3);
137 g_input = input; 194 g_input = input;
195 install_input_hook();
138 return true; 196 return true;
139 } 197 }
140 } 198 }