Skip to content

Commit 90a6714

Browse files
authored
Fix things (for CS:S) after 2025-02-18 update (#1226)
* some wip windows gamedata * maybe correct cstrike x32 linux gamedata * update some offsets with x64 versions * x64 offsets for ladder things * maybe okay x64 css sigs * fill out the OS and X64 offsets more * A few typos * Try to fix m_surfaceFriction for TAS * rolls around on the floor groaning * remove unnecessary CHECKED comments in gamedata * update workflow versions * Migrate from ProcessMovement/ProcessMovementPost to PreThink/PostThinkPost * Revert "Migrate from ProcessMovement/ProcessMovementPost to PreThink/PostThinkPost" This reverts commit c829a78. * Make sure MaybeDoPhysicsUntouch() is called in ProcessMovementPost * misc * Prevent changing sv_autobunnyhoping (like via .cfg files) * Don't break CSGO TAS yet * Edit some gamedata comments
1 parent 8ecc2a7 commit 90a6714

File tree

5 files changed

+151
-50
lines changed

5 files changed

+151
-50
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
runs-on: ubuntu-latest
88
strategy:
99
matrix:
10-
sm-version: [ '1.11', '1.12' ]
10+
sm-version: [ '1.12' ]
1111

1212
name: "Build SM ${{ matrix.sm-version }}"
1313
steps:
@@ -28,10 +28,10 @@ jobs:
2828
# Mac zip just because it's smaller & we don't repack the extensions...
2929
wget https://github.com/ErikMinekus/sm-ripext/releases/download/1.3.1/sm-ripext-1.3.1-mac.zip
3030
unzip sm-ripext-1.3.1-mac.zip "addons/sourcemod/scripting/include/*"
31-
wget https://github.com/clugg/sm-json/archive/refs/tags/v5.0.0.tar.gz
32-
tar --strip-components=1 -xvzf v5.0.0.tar.gz sm-json-5.0.0/addons/sourcemod/scripting/include
33-
wget https://github.com/hermansimensen/eventqueue-fix/archive/refs/tags/1.3.2.tar.gz
34-
tar --strip-components=1 -xvzf 1.3.2.tar.gz -C addons/sourcemod
31+
wget https://github.com/clugg/sm-json/archive/refs/tags/v5.0.1.tar.gz
32+
tar --strip-components=1 -xvzf v5.0.1.tar.gz sm-json-5.0.1/addons/sourcemod/scripting/include
33+
wget https://github.com/hermansimensen/eventqueue-fix/archive/refs/heads/main.tar.gz
34+
tar --strip-components=1 -xvzf main.tar.gz -C addons/sourcemod
3535
rm -rf *.zip *.tar.gz addons/sourcemod/.git* addons/sourcemod/LICENSE
3636
3737
- name: Run compiler

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Includes a records system, map zones (start/end marks etc), bonuses, HUD with us
1818

1919
# Requirements:
2020
* Steam version of Counter-Strike: Source, Counter-Strike: Global Offensive, or Team Fortress 2.
21-
* [Metamod:Source](https://www.sourcemm.net/downloads.php?branch=stable) and [SourceMod](https://www.sourcemod.net/downloads.php?branch=stable) 1.11 or higher.
21+
* [Metamod:Source](https://www.sourcemm.net/downloads.php?branch=stable) and [SourceMod](https://www.sourcemod.net/downloads.php?branch=stable) 1.12 or higher.
2222
* A MySQL database (preferably locally hosted) if your database is likely to grow big, or if you want to use the rankings plugin. MySQL server version of 5.5.5 or above (MariaDB equivalent works too) is required.
2323

2424
# Optional requirements, for the best experience:

addons/sourcemod/gamedata/shavit.games.txt

Lines changed: 110 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@
1515
{
1616
"library" "server"
1717
"windows" "@CreateInterface"
18+
"windows64" "@CreateInterface"
1819
"linux" "@CreateInterface"
20+
"linux64" "@CreateInterface"
1921
}
2022

2123
"CreateInterface_Engine"
2224
{
2325
"library" "engine"
2426
"windows" "@CreateInterface"
27+
"windows64" "@CreateInterface"
2528
"linux" "@CreateInterface"
29+
"linux64" "@CreateInterface"
2630
}
2731
}
2832

@@ -31,13 +35,25 @@
3135
"OS"
3236
{
3337
"windows" "1"
38+
"windows64" "1"
3439
"linux" "2"
40+
"linux64" "2"
41+
}
42+
43+
"X64"
44+
{
45+
"windows" "0"
46+
"windows64" "1"
47+
"linux" "0"
48+
"linux64" "1"
3549
}
3650

3751
"ProcessMovement"
3852
{
3953
"windows" "1"
54+
"windows64" "1"
4055
"linux" "2"
56+
"linux64" "2"
4157
}
4258
}
4359
}
@@ -151,64 +167,104 @@
151167
{
152168
"Addresses"
153169
{
154-
"m_surfaceFriction"
155-
{
156-
"signature" "CBasePlayer->m_surfaceFriction"
157-
"read" "2" // skip the first 2 bytes
158-
}
159170
}
160171

161172
"Offsets"
162173
{
163-
// https://asherkin.github.io/vtable/
174+
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
175+
// search string: "func_pushable" and you can find CBaseTrigger::PassesTriggerFilters / CBaseVPhysicsTrigger::PassesTriggerFilters. Follow references to these functions to find the vtable and then calculate the offset...
164176
"CBaseTrigger::PassesTriggerFilters"
165177
{
166-
"windows" "197"
167-
"linux" "198"
178+
"windows" "203"
179+
"windows64" "203"
180+
"linux" "204"
181+
"linux64" "204"
168182
}
169-
// https://asherkin.github.io/vtable/
183+
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
184+
// search string: "start %f %f %f" and then check the function call offsets above it and convert them to vtable offsets (divide by 4 most likely or whatever)
170185
"CCSPlayer::GetPlayerMaxSpeed"
171186
{
172-
"windows" "438"
173-
"linux" "439"
174-
"mac" "439"
187+
"windows" "445"
188+
"windows64" "445"
189+
"linux" "446"
190+
"linux64" "446"
175191
}
176-
// https://asherkin.github.io/vtable/
192+
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
193+
// search string: "Invalid counterterrorist spawnpoint" and then look for the first function call in each iteration of the loop
177194
"CGameRules::IsSpawnPointValid"
178195
{
179196
"windows" "76"
197+
"windows64" "77" // yes, same as linux64 (according to vtable site)
180198
"linux" "77"
181-
"mac" "77"
199+
"linux64" "77"
182200
}
183-
// https://asherkin.github.io/vtable/
201+
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
202+
// search string: "water" to find CBasePlayer::UpdateStepSound. At the bottom there's a vtable call to ::PlayStepSound. Grab that, divide by 4, subtract 1. Bam, UpdateStepSound...
184203
"CBasePlayer::UpdateStepSound"
185204
{
186-
"windows" "358"
187-
"linux" "359"
205+
"windows" "364"
206+
"windows64" "364"
207+
"linux" "365"
208+
"linux64" "365"
188209
}
189210
// find in CCSGameMovement::CheckForLadders which references CCSPlayer::CanGrabLadder
211+
//
212+
// Find CCSPlayer::CanGrabLadder by searching for 4096.0f, then find the function (CheckForLadders) that references it...
213+
// CanGrabLadder might look like this on Windows (or just use symbols on Linux)
214+
// undefined4 __thiscall CCSPlayer::CanGrabLadder(int param_1_00,float *param_1,float *param_2)
215+
// {
216+
// float10 extraout_ST0;
217+
// float fVar1;
218+
// float fVar2;
219+
//
220+
// (*(code *)**(undefined4 **)(param_1_00 + 0x1790))();
221+
// if ((float10)0 < (float10)*(float *)(param_1_00 + 0x1798) - extraout_ST0) {
222+
// fVar1 = *param_1 - *(float *)(param_1_00 + 0x17a8);
223+
// fVar2 = param_1[1] - *(float *)(param_1_00 + 0x17ac);
224+
// if (fVar2 * fVar2 + fVar1 * fVar1 < 4096.0) {
225+
// return 0;
226+
// }
227+
// if ((((NAN(*(float *)(param_1_00 + 0x179c)) || NAN(*param_2)) !=
228+
// (*(float *)(param_1_00 + 0x179c) == *param_2)) &&
229+
// ((NAN(*(float *)(param_1_00 + 0x17a0)) || NAN(param_2[1])) !=
230+
// (*(float *)(param_1_00 + 0x17a0) == param_2[1]))) &&
231+
// ((NAN(*(float *)(param_1_00 + 0x17a4)) || NAN(param_2[2])) !=
232+
// (*(float *)(param_1_00 + 0x17a4) == param_2[2]))) {
233+
// return 0;
234+
// }
235+
// }
236+
// return 1;
237+
// }
190238
"CCSPlayer::m_lastStandingPos"
191239
{
192-
"windows" "5684"
193-
"linux" "5704" // +20 wow that's easy!
240+
"windows" "6016"
241+
"windows64" "6640"
242+
"linux" "6036" // +20 wow that's easy!
243+
"linux64" "6688" // +48 wow that's easy!
194244
}
195245
// find CCSPlayer::CanGrabLadder via 4096.0f or symbols on linux...
196246
"CCSPlayer::m_ladderSurpressionTimer"
197247
{
198-
"windows" "5700"
199-
"linux" "5720" // +20 wow that's easy!
248+
"windows" "6032"
249+
"windows64" "6668"
250+
"linux" "6052" // +20 wow that's easy!
251+
"linux64" "6716" // +48 wow that's easy!
200252
}
201253
// find CCSPlayer::CanGrabLadder via 4096.0f or symbols on linux...
202254
"CCSPlayer::m_lastLadderNormal"
203255
{
204-
"windows" "5712"
205-
"linux" "5732" // +20 wow that's easy!
256+
"windows" "6044"
257+
"windows64" "6672"
258+
"linux" "6064" // +20 wow that's easy!
259+
"linux64" "6720" // +48 wow that's easy!
206260
}
207261
// find CCSPlayer::CanGrabLadder via 4096.0f or symbols on linux...
208262
"CCSPlayer::m_lastLadderPos"
209263
{
210-
"windows" "5724"
211-
"linux" "5744" // +20 wow that's easy!
264+
"windows" "6056"
265+
"windows64" "6684"
266+
"linux" "6076" // +20 wow that's easy!
267+
"linux64" "6732" // +48 wow that's easy!
212268
}
213269
// TODO
214270
"GetClusterForOrigin"
@@ -226,53 +282,69 @@
226282

227283
"Signatures"
228284
{
229-
// search string: "ReloadEffect" to find CWeaponCSBase::SendReloadEvents and then DoAnimationEvent is probably the second to last function called there.
285+
// search string: "ReloadEffect" to find CWeaponCSBase::SendReloadEvents and then CCSPlayer::DoAnimationEvent is probably the second to last function called there.
230286
"Player::DoAnimationEvent"
231287
{
232-
"windows" "\x55\x8B\xEC\x83\xEC\x10\x89\x4D\xFC\x83\x7D\x08\x02"
288+
"windows" "\x55\x8B\xEC\x83\xEC\x0C\x89\x4D\x2A\x83\x7D\x2A\x02"
289+
"windows64" "\x44\x89\x44\x24\x2A\x89\x54\x24\x2A\x48\x89\x4C\x24\x2A\x48\x83\xEC\x38\x83\x7C\x24\x2A\x02"
233290
"linux" "@_ZN9CCSPlayer16DoAnimationEventE17PlayerAnimEvent_ti"
291+
"linux64" "@_ZN9CCSPlayer16DoAnimationEventE17PlayerAnimEvent_ti"
234292
}
235-
// search string: "-nobots"
293+
// search string: "-nobots" (and then look for the function that also references "fill" and "match" (or just the function with 0 or 1 parameters...))
236294
"BotManager::MaintainBotQuota"
237295
{
238296
"windows" "\x55\x8B\xEC\x83\xEC\x14\xFF\x15"
297+
"windows64" "\x48\x83\xEC\x78\xFF\x15"
239298
"linux" "@_ZN13CCSBotManager16MaintainBotQuotaEv"
299+
"linux64" "@_ZN13CCSBotManager16MaintainBotQuotaEv"
240300
}
241-
// search string: "Server is hibernating" to find SetHibernating and then go its references
301+
// search string: "Server is hibernating" to find SetHibernating and then go to its references
302+
// NOTE 2025-02-19: Function has been inlined on Windows into SV_Think...
242303
"CGameServer::UpdateHibernationState"
243304
{
244305
"library" "engine"
245-
"windows" "\x55\x8B\xEC\x83\xEC\x08\x57\x8B\xF9\x8B\x07\x8B\x40\x2A\xFF\xD0\x84\xC0\x0F\x84"
246-
"linux" "@_ZN11CGameServer22UpdateHibernationStateEv"
306+
//"windows" ""
307+
"windows64" "\x48\x89\x5C\x24\x2A\x56\x48\x83\xEC\x40\x8B\x05"
308+
"linux" "@_ZN11CGameServer22UpdateHibernationStateEv.part.0"
309+
"linux64" "@_ZN11CGameServer14SetHibernatingEb"
247310
}
248311
// search string: "remove 0x%p: %s-%s" to find PhysicsRemoveToucher.
249312
// Find PhysicsCheckForEntityUntouch by checking the functions that call PhysicsRemoveToucher.
313+
// (should be the function with one argument (this ptr))
250314
"PhysicsCheckForEntityUntouch"
251315
{
252-
"windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86"
316+
"windows" "\x55\x8B\xEC\x83\xEC\x08\x57\x8B\xF9\x8B\x87"
317+
"windows64" "\x40\x57\x48\x83\xEC\x20\x8B\x81"
253318
"linux" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv"
319+
"linux64" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv"
254320
}
255-
// search string: "Could not add bot to the game: Team is full"
321+
// search string: "Could not add bot to the game: Team is full" to find CCSBotManager::BotAddCommand and then follow the if-statement up to find the function call that was full (because TeamFull())
256322
// protip: on csgo we just use mp_randomspawn instead.
257323
"CCSGameRules::TeamFull"
258324
{
259325
"windows" "\x55\x8B\xEC\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x8B\x45\x2A\x83\xE8\x02"
326+
"windows64" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x20\x8B\xFA\x48\x8B\xD9\xE8\x2A\x2A\x2A\x2A\x83\xEF\x02"
260327
"linux" "@_ZN12CCSGameRules8TeamFullEi"
328+
"linux64" "@_ZN12CCSGameRules8TeamFullEi"
261329
}
262330
// search string: "remove 0x%p: %s-%s (%d-%d) [%d in play, %d max]\n".
263331
// function with one argument is PhysicsRemoveTouchedList
264332
"PhysicsRemoveTouchedList"
265333
{
266-
"windows" "\x55\x8B\xEC\x83\xEC\x08\x57\x8B\x7D\x08\x8B\x87\x2A\x2A\x2A\x2A\xD1\xE8\xA8\x01\x0F\x84"
334+
"windows" "\x55\x8B\xEC\x83\xEC\x08\x53\x8B\x5D\x2A\x8B\x83"
335+
"windows64" "\x40\x55\x56\x48\x83\xEC\x58"
267336
"linux" "@_ZN11CBaseEntity24PhysicsRemoveTouchedListEPS_"
337+
"linux64" "@_ZN11CBaseEntity24PhysicsRemoveTouchedListEPS_"
268338
}
269-
// look for function CGameMovement::CategorizePosition
270-
// and you will see something something *(_DWORD*)(a1[1] + some_offset) = 0x3F800000
339+
// look for CGameMovement::CategorizePosition by searching for 140.0f
340+
// and you will see something something `*(_DWORD*)(a1[1] + some_offset) = 0x3F800000` right at the top
271341
// make a signature at "mov dword ptr[eax+some_offset], 3F800000h"
272342
"CBasePlayer->m_surfaceFriction"
273343
{
274-
"windows" "\xC7\x80\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x8B\x07\xFF\x90"
275-
"linux" "\xC7\x80\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x8B\x03\x89\x1C\x24\xFF\x90\x2A\x2A\x2A\x2A\x8B\x53\x04"
344+
"windows" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x8B\x07"
345+
"windows64" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x48\x8B\x01"
346+
"linux" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x8B\x03"
347+
"linux64" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x48\x8B\x07"
276348
}
277349
}
278350
}

addons/sourcemod/scripting/shavit-core.sp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,11 @@ public void OnPluginStart()
292292
gB_Protobuf = (GetUserMessageType() == UM_Protobuf);
293293

294294
sv_autobunnyhopping = FindConVar("sv_autobunnyhopping");
295-
if (sv_autobunnyhopping) sv_autobunnyhopping.BoolValue = false;
295+
if (sv_autobunnyhopping)
296+
{
297+
sv_autobunnyhopping.BoolValue = false;
298+
sv_autobunnyhopping.AddChangeHook(OnConVarChanged);
299+
}
296300

297301
if (gEV_Type != Engine_CSGO && gEV_Type != Engine_CSS && gEV_Type != Engine_TF2)
298302
{
@@ -520,7 +524,7 @@ void LoadDHooks()
520524
SetFailState("Failed to get ProcessMovement offset");
521525
}
522526

523-
Handle processMovement = DHookCreate(offset, HookType_Raw, ReturnType_Void, ThisPointer_Ignore, DHook_ProcessMovement);
527+
Handle processMovement = DHookCreate(offset, HookType_Raw, ReturnType_Void, ThisPointer_Ignore, DHook_ProcessMovementPre);
524528
DHookAddParam(processMovement, HookParamType_CBaseEntity);
525529
DHookAddParam(processMovement, HookParamType_ObjectPtr);
526530
DHookRaw(processMovement, false, IGameMovement);
@@ -597,6 +601,13 @@ void LoadDHooks()
597601

598602
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
599603
{
604+
if (convar == sv_autobunnyhopping)
605+
{
606+
if (convar.BoolValue)
607+
convar.BoolValue = false;
608+
return;
609+
}
610+
600611
gB_StyleCookies = (newValue[0] != '!');
601612
gI_DefaultStyle = StringToInt(newValue[1]);
602613
}
@@ -3088,7 +3099,7 @@ public MRESReturn DHook_PreventBunnyJumpingPre()
30883099
return MRES_Ignored;
30893100
}
30903101

3091-
public MRESReturn DHook_ProcessMovement(Handle hParams)
3102+
public MRESReturn DHook_ProcessMovementPre(Handle hParams)
30923103
{
30933104
int client = DHookGetParam(hParams, 1);
30943105
gI_ClientProcessingMovement = client;
@@ -3204,6 +3215,8 @@ public MRESReturn DHook_ProcessMovementPost(Handle hParams)
32043215
Call_PushCell(time);
32053216
Call_Finish();
32063217

3218+
MaybeDoPhysicsUntouch(client);
3219+
32073220
return MRES_Ignored;
32083221
}
32093222

addons/sourcemod/scripting/shavit-tas.sp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,32 @@ public void OnPluginStart()
114114

115115
GameData gamedata = new GameData("shavit.games");
116116

117-
Address surfaceFrctionAddress = gamedata.GetAddress("m_surfaceFriction");
117+
Address surfaceFrictionAddress;
118118

119-
if (surfaceFrctionAddress == Address_Null)
119+
if (gEV_Type == Engine_CSGO)
120+
surfaceFrictionAddress = gamedata.GetAddress("m_surfaceFriction");
121+
else
122+
surfaceFrictionAddress = gamedata.GetMemSig("CBasePlayer->m_surfaceFriction");
123+
124+
if (surfaceFrictionAddress == Address_Null)
120125
{
121126
g_iSurfaceFrictionOffset = -1;
122127
LogError("[XUTAX] The address of m_surfaceFriction is null, defaulting friction values");
123128
}
124129
else
125130
{
126-
g_iSurfaceFrictionOffset = view_as<int>(surfaceFrctionAddress);
131+
if (gEV_Type == Engine_CSGO)
132+
{
133+
g_iSurfaceFrictionOffset = view_as<int>(surfaceFrictionAddress);
134+
}
135+
else
136+
{
137+
int instr = LoadFromAddress(surfaceFrictionAddress, NumberType_Int32);
138+
// The lowest two bytes are the beginning of a `mov`.
139+
// The offset is 100% definitely totally always 16-bit.
140+
// We could just put the offset into the gamedata too but SHUT UP!
141+
g_iSurfaceFrictionOffset = instr >> 16;
142+
}
127143
}
128144

129145
delete gamedata;

0 commit comments

Comments
 (0)