From 2a6ee99cfdbc9d94da005f7a618d4e6425c075e5 Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 26 Mar 2026 04:10:56 -0400 Subject: [PATCH 01/32] Migrate gamedata to JSONC & IDA signature formats --- PackageScript | 4 +- gamedata/cs2fixes.games.txt | 558 ------------------------------------ gamedata/cs2fixes.jsonc | 553 +++++++++++++++++++++++++++++++++++ src/cs2fixes.cpp | 17 +- src/gameconfig.cpp | 207 +++++++------ src/gameconfig.h | 21 +- src/mempatch.cpp | 2 +- 7 files changed, 697 insertions(+), 665 deletions(-) delete mode 100644 gamedata/cs2fixes.games.txt create mode 100644 gamedata/cs2fixes.jsonc diff --git a/PackageScript b/PackageScript index cda3090e0..44cfacd19 100644 --- a/PackageScript +++ b/PackageScript @@ -121,7 +121,7 @@ for task in MMSPlugin.binaries: builder.AddCopy(os.path.join('configs', 'zr', 'weapons.cfg.example'), zr_folder) builder.AddCopy(os.path.join('configs', 'zr', 'hitgroups.cfg.example'), zr_folder) builder.AddCopy(os.path.join('configs', 'entwatch', 'maps', 'template.jsonc'), ew_maps_folder) - builder.AddCopy(os.path.join('gamedata', 'cs2fixes.games.txt'), gamedata_folder) + builder.AddCopy(os.path.join('gamedata', 'cs2fixes.jsonc'), gamedata_folder) particles_cs2f_folder = builder.AddFolder(os.path.join(packages[sdk_name].sdk_name, 'particles', MMSPlugin.metadata['name'])) builder.AddCopy(os.path.join('assets', 'particles', MMSPlugin.metadata['name'], 'admin_beacon.vpcf_c'), particles_cs2f_folder) @@ -169,4 +169,4 @@ for task in MMSPlugin.binaries: # Generate PDB info. with open(os.path.join(builder.buildPath, 'pdblog.txt'), 'wt') as fp: for line in pdb_list: - fp.write(line.path + '\n') \ No newline at end of file + fp.write(line.path + '\n') diff --git a/gamedata/cs2fixes.games.txt b/gamedata/cs2fixes.games.txt deleted file mode 100644 index d417e3131..000000000 --- a/gamedata/cs2fixes.games.txt +++ /dev/null @@ -1,558 +0,0 @@ -"Games" -{ - "csgo" - { - "Signatures" - { - // Called from Host_Say - "UTIL_SayTextFilter" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x74\x24\x2A\x48\x89\x7C\x24\x2A\x55\x41\x56\x41\x57\x48\x8D\x6C\x24\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x49\x8B\xF8" - "linux" "\x55\x48\x8D\x05\x2A\x2A\x2A\x2A\x48\x89\xE5\x41\x57\x41\x56\x4C\x8D\x75\x2A\x41\x55\x41\x89\xCD\x41\x54\x49\x89\xD4" - } - // Called from Host_Say - "UTIL_SayText2Filter" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x74\x24\x2A\x48\x89\x7C\x24\x2A\x55\x41\x56\x41\x57\x48\x8D\x6C\x24\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x45\x0F\xB6\xF0" - "linux" "\x55\x48\x8D\x05\x2A\x2A\x2A\x2A\x48\x89\xE5\x41\x57\x41\x56\x41\x89\xD6\x31\xD2" - } - "IsHearingClient" - { - "library" "engine" - "windows" "\x40\x53\x48\x83\xEC\x2A\x48\x8B\xD9\x3B\x51" - "linux" "\x55\x48\x89\xE5\x41\x56\x41\x55\x41\x54\x53\x48\x89\xFB\x39\x77" - } - // idk a good way to find this again, i just brute forced the vtable. offset is 136 on CTriggerPush - "TriggerPush_Touch" - { - "library" "server" - "windows" "\x40\x55\x53\x57\x48\x8D\x6C\x24\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8B\x02\x48\x8B\xF9" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x2A\xE8\x2A\x2A\x2A\x2A\x84\xC0" - } - // this is called in CTriggerPush::Touch, using IDA pseudocode look in an `if ( ( v & 0x80 ) != 0 )` and then `if ( v > 0.0 ) SetGroundEntity()` - "SetGroundEntity" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x55\x56\x57\x41\x55\x41\x57\x48\x83\xEC\x2A\x44\x8B\x89" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xD5\x41\x54\x49\x89\xF4\x53\x48\x89\xFB\x48\x83\xEC\x2A\x8B\x87" - } - // Check vauff's pin in #scripting - "ServerMovementUnlock" - { - "library" "server" - "windows" "\x0F\x86\xAF\x2A\x2A\x2A\x0F\x57\xC0\x0F\x2E\xC2" - "linux" "\x0F\x87\x2A\x2A\x2A\x2A\xF3\x0F\x10\x3D\x2A\x2A\x2A\x2A\xF3\x0F\x11\xBD\x2A\x2A\x2A\x2A\x48\x89\xDE" - } - // String: "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam - "CCSPlayerController_SwitchTeam" - { - "library" "server" - "windows" "\x40\x53\x57\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8B\xD9\x8B\xFA" - "linux" "\x55\x48\x89\xE5\x41\x54\x49\x89\xFC\x89\xF7" - } - // String: "player_jump", then find 42C80000h or in pseudocode "*(a2 + 68) = 1120403456;", changing from 100 to 145 - "CheckJumpButtonWater" - { - "library" "server" - "windows" "\xC8\x42\xEB\x2A\x4C\x8B\x77\x2A\x4D\x39\x6E" - "linux" "\xC8\x42\x41\xC7\x84\x24\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x41\xC7\x84\x24\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xE9" - } - // Called right after "Removed %s(%s)\n" - "UTIL_Remove" - { - "library" "server" - "windows" "\x48\x85\xC9\x74\x2A\x48\x8B\xD1\x48\x8B\x0D\x2A\x2A\x2A\x2A" - "linux" "\x48\x89\xFE\x48\x85\xFF\x74\x2A\x48\x8D\x05\x2A\x2A\x2A\x2A\x48" - } - // "SetPosition" is passed to this - "CEntitySystem_AddEntityIOEvent" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x18\x4C\x89\x4C\x24\x20\x48\x89\x4C\x24\x08\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x20" - "linux" "\x55\x48\x89\xE5\x41\x55\x49\x89\xCD\x41\x54\x49\x89\xFC\x53\xBB" - } - // "BombPlanted" is passed to this - "CEntityInstance_AcceptInput" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x74\x24\x2A\x57\x48\x83\xEC\x2A\x49\x8B\xF0\x48\x8B\xD9\x48\x8B\x0D" - "linux" "\x55\x48\x89\xF0\x48\x89\xE5\x41\x57\x49\x89\xFF\x41\x56\x48\x8D\x7D" - } - // Called by CEntityInstance_AcceptInput - "CEntityIdentity_AcceptInput" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x54\x24\x2A\x48\x89\x4C\x24\x2A\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x2A\x2A\x2A\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8B\x02" - "linux" "\x55\x49\x89\xD3\x48\x89\xE5\x41\x57\x45\x89\xCF\x41\x56" - } - // func_pushable inside CTriggerBrush::Use calls CEntityIOOutput::FireOutputInternal - // Windows - https://imgur.com/a/A3zcxQm - // Linux doesn't inline it so you need to find any of the xrefs and the proper function is right after it. - // You can tell it apart by the arguments: (a1 + 2616, v4, a1, &v6, 0.0); - "CEntityIOOutput_FireOutputInternal" - { - "library" "server" - "windows" "\x4C\x89\x4C\x24\x2A\x48\x89\x4C\x24\x2A\x53\x56" - "linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xFF\x41\x56\x41\x55\x41\x54\x49\x89\xD4\x53\x48\x89\xF3\x48\x83\xEC\x2A\x48\x8D\x05" - } - // "multi_manager" is passed to this - "CGameEntitySystem_FindEntityByClassName" - { - "library" "server" - "windows" "\x48\x83\xEC\x68\x45\x33\xC9" - "linux" "\x55\x45\x31\xC0\x31\xC9\x48\x89\xE5\x53\x48\x8D\x5D\x2A\x48\x83\xEC\x2A\x48\x89\xDF" - } - // "commentary_semaphore" is passed to this - "CGameEntitySystem_FindEntityByName" - { - "library" "server" - "windows" "\x48\x81\xEC\x88\x2A\x2A\x2A\x4D\x85\xC0" - "linux" "\x55\x48\x89\xE5\x41\x54\x53\x48\x83\xEC\x2A\x48\x85\xD2" - } - // "CBaseEntity::TakeDamageOld" - "CBaseEntity_TakeDamageOld" - { - "library" "server" - "windows" "\x40\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8D\x6C\x24\x2A\x48\x89\x9D\x2A\x2A\x2A\x2A\x45\x33\xED" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xFD\x41\x54\x49\x89\xF4\x53\x48\x89\xD3\x48\x83\xEC\x2A\x48\x85\xD2" - } - // Should be xref'd right above "flGravity", takes a float arg - "CBaseEntity::SetGravityScale" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x2A\xF3\x0F\x10\x81\x2A\x2A\x2A\x2A\x48\x8B\xF9\x0F\x29\x74\x24\x2A\x0F\x28\xF1\x0F\x2E\xC6\x7A\x2A\x74" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x89\xFB\x48\x81\xEC\x2A\x2A\x2A\x2A\x0F\x2E\x87\x2A\x2A\x2A\x2A\x7A\x2A\x75\x2A\x48\x81\xC4\x2A\x2A\x2A\x2A\x5B\x41\x5C\x41\x5D\x41\x5E\x41\x5F\x5D\xC3\x0F\x1F\x40\x2A\x31\xC9\x31\xF6\x31\xFF\xF3\x0F\x11\x85\x2A\x2A\x2A\x2A\x66\x89\x8D\x2A\x2A\x2A\x2A\xBA\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\x66\x0F\xEF\xC9\x48\xC7\x85\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x48\xC7\x85\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x48\xC7\x85\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x48\xC7\x85\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x0F\x29\x8D\x2A\x2A\x2A\x2A\x48\xC7\x85\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xC7\x85\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xF3\x0F\x10\x85\x2A\x2A\x2A\x2A\x85\xC0\x41\x89\xC4\x0F\x8E\x2A\x2A\x2A\x2A\x48\x63\x8D\x2A\x2A\x2A\x2A\x48\x63\xD0\x31\xF6\xF3\x0F\x11\x85\x2A\x2A\x2A\x2A\x48\xC1\xE2\x2A\x48\x8B\xBD\x2A\x2A\x2A\x2A\x48\xC1\xE1\x2A\x81\xBD\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x40\x0F\x96\xC6\xE8\x2A\x2A\x2A\x2A\x8B\x95\x2A\x2A\x2A\x2A\xF3\x0F\x10\x85\x2A\x2A\x2A\x2A\x48\x89\x85\x2A\x2A\x2A\x2A\x81\xFA\x2A\x2A\x2A\x2A\x0F\x87" - } - // "Game System %s is defined twice!\n" - // Note that this signature points to the instruction with sm_pFirst which is the first qword referenced in the function. - "IGameSystem_InitAllSystems_pFirst" - { - "library" "server" - "windows" "\x48\x8B\x1D\x2A\x2A\x2A\x2A\x48\x85\xDB\x0F\x84\x2A\x2A\x2A\x2A\xBD" - "linux" "\x4C\x8B\x35\x2A\x2A\x2A\x2A\x4D\x85\xF6\x75\x2A\xE9" - } - // Windows "%s: IGameSystem::LoopPostInitAllSystems(start)\n" - // Linux "%s: IGameSystem::LoopInitAllSystems(start)" - // In windows it's the only qword that gets nullchecked, while in linux it gets set to another qword's address - "IGameSystem_LoopPostInitAllSystems_pEventDispatcher" - { - "library" "server" - "windows" "\x48\x39\x1D\x2A\x2A\x2A\x2A\x74\x2A\x39\x05" - "linux" "\x4C\x8B\x25\x2A\x2A\x2A\x2A\x48\x8B\x05\x2A\x2A\x2A\x2A\x8B\x35" - } - // "--CLoopModeGame::SetWorldSession" - // In the above, a number is checked if > 0 then the function is called - "IGameSystem_LoopDestroyAllSystems_s_GameSystems" - { - "library" "server" - "windows" "\x8B\x05\x2A\x2A\x2A\x2A\x83\xE8\x2A\x48\x63\xF8\x0F\x88" - "linux" "\x8B\x05\x2A\x2A\x2A\x2A\x89\xC2\x83\xEA\x2A\x0F\x88\x2A\x2A\x2A\x2A\x4C\x8D\x3D" - } - "CBasePlayerController_SetPawn" - { - "library" "server" - "windows" "\x44\x88\x4C\x24\x2A\x53\x57\x41\x54\x41\x56\x41\x57\x48\x83\xEC" - "linux" "\x55\x48\x8D\x87\x2A\x2A\x2A\x2A\x48\x89\xE5\x41\x57\x41\x89\xCF" - } - // String: "CNavMesh::GetNearestNavArea" - "CNavMesh_GetNearestNavArea" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x44\x89\x4C\x24\x2A\x48\x89\x54\x24\x2A\x48\x89\x4C\x24\x2A\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24" - "linux" "\x55\x48\x8D\x05\x2A\x2A\x2A\x2A\x48\x89\xE5\x41\x57\x41\x56\x49\x89\xFE\x41\x55\x48\x8D\x3D" - } - // Search "Changes's player's model", look for a function containing 'models/%s.vmdl'. Below V_snprintf is the one - // This matches 2 functions, however they're literally identical - "CBaseModelEntity_SetModel" - { - "library" "server" - "windows" "\x40\x53\x48\x83\xEC\x2A\x48\x8B\xD9\x4C\x8B\xC2\x48\x8B\x0D\x2A\x2A\x2A\x2A\x48\x8D\x54\x24\x2A\x48\x8B\x01\xFF\x50\x2A\x48\x8B\x44\x24" - "linux" "\x55\x48\x89\xF2\x48\x89\xE5\x53\x48\x89\xFB\x48\x8D\x7D\x2A\x48\x83\xEC\x2A\x48\x8D\x05\x2A\x2A\x2A\x2A\x48\x8B\x30\x48\x8B\x06" - } - "CGameRules_TerminateRound" - { - "library" "server" - "windows" "\x48\x8B\xC4\x4C\x89\x48\x2A\x48\x89\x48\x2A\x55\x56\x41\x56" - "linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xFF\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8D\x05\x2A\x2A\x2A\x2A\xF3\x0F\x11\x85" - } - "CCSPlayer_WeaponServices_CanUse" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x56\x57\x41\x56\x48\x83\xEC\x2A\x48\x8B\x01\x48\x8B\xFA" - "linux" "\x55\x48\x8D\x15\x2A\x2A\x2A\x2A\x48\x89\xE5\x41\x55\x41\x54\x49\x89\xFC\x53\x48\x89\xF3\x48\x83\xEC\x2A\x48\x8B\x07\x48\x8B\x80" - } - "CCSPlayer_WeaponServices_EquipWeapon" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x2A\x48\x83\x79\x2A\x2A\x48\x8B\xFA\x48\x8B\xD9\x75\x2A\xE8\x2A\x2A\x2A\x2A\x48\x8B\x53" - "linux" "\x55\x48\x89\xE5\x41\x55\x41\x54\x49\x89\xFC\x53\x48\x89\xF3\x48\x83\xEC\x2A\x48\x8B\x77" - } - "CreateEntityByName" - { - "library" "server" - "windows" "\x48\x83\xEC\x48\xC6\x44\x24\x30\x00" - "linux" "\x48\x8D\x05\x2A\x2A\x2A\x2A\x55\x48\x89\xFA" - } - "DispatchSpawn" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x10\x57\x48\x83\xEC\x30\x48\x8B\xDA\x48\x8B\xF9\x48\x85\xC9" - "linux" "\x48\x85\xFF\x74\x2A\x55\x48\x89\xE5\x41\x55\x49\x89\xFD" - } - // Look for "SetEntityName", that will be the vscript binding definition - // Scroll a bit down and you'll find something like this (note the offset): *(_QWORD *)(v453 + 64) = sub_1807B0350; - // that function is just a jump to the one we want - "CEntityIdentity_SetEntityName" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x10\x57\x48\x83\xEC\x20\x48\x8B\xD9\x4C\x8B\xC2" - "linux" "\x55\x48\x89\xF2\x48\x89\xE5\x41\x55\x41\x54\x53" - } - // "Error - cannot add bots after game is over." - "BotNavIgnore" - { - "library" "server" - "windows" "\x0F\x84\x2A\x2A\x2A\x2A\x80\xB8\x2A\x2A\x2A\x2A\x00\x0F\x84\x2A\x2A\x2A\x2A\x80\x3D\x2A\x2A\x2A\x2A\x00\x74\x15" - "linux" "\x0F\x84\x2A\x2A\x2A\x2A\x44\x0F\xB6\xB0\x2A\x2A\x2A\x2A\x45\x84\xF6\x0F\x84" - } - // next to "soundname", in windows it's the last referenced sub while in linux it's right after - // this is a vscript binding though so it may be removed in the future? - "CBaseEntity_EmitSoundParams" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x74\x24\x2A\x48\x89\x7C\x24\x2A\x55\x48\x8B\xEC\x48\x81\xEC\x2A\x2A\x2A\x2A\x33\xC0" - "linux" "\x48\xB8\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x55\x0F\x28\xD0" - } - // "ParticleEffect", found in a function with 9 arguments - "DispatchParticleEffect" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x48\x89\x7C\x24\x18\x4C\x89\x74\x24\x20\x55\x48\x8D\x6C\x24\xD1" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x41\x89\xCC\x53\x48\x89\xD3" - } - // search for "land_%s", this is called after that string is referenced (the one with 4 parameters). - // (function that calls it also contains "T_Default.SuitLand"). - "CBaseEntity_EmitSoundFilter" - { - "library" "server" - "windows" "\x40\x53\x48\x83\xEC\x2A\x4C\x89\x4C\x24\x2A\x48\x8B\xD9\x45\x8B\xC8" - "linux" "\x55\x48\x89\xE5\x53\x48\x89\xFB\x48\x83\xEC\x2A\xE8\x2A\x2A\x2A\x2A\x48\x89\xD8\x48\x8B\x5D\x2A\xC9\xC3\xCC\xCC\xCC\xCC\xCC\xCC\x48\xB8" - } - // "PlayerMovementTraces" - "ProcessMovement" - { - "library" "server" - "windows" "\x40\x57\x41\x57\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x83\x79" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x2A\x48\x8B\x7F" - } - // "env_shake %s with", in either xref there will be a call to SetMoveType(a1, 0, 0) at the top - "CBaseEntity_SetMoveType" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x48\x89\x74\x24\x2A\x48\x89\x7C\x24\x2A\x41\x56\x48\x83\xEC\x2A\x41\x0F\xB6\xF0" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x41\x89\xD4\x53\x48\x89\xFB\x48\x81\xEC\x2A\x2A\x2A\x2A\x40\x38\xB7" - } - // Use CBaseEntity::Use offset - // This signature points directly to the instruction to patch - "CPhysBox_Use" - { - "library" "server" - "windows" "\x4C\x8B\x43\x2A\x48\x8D\x8F\x2A\x2A\x2A\x2A\x48\x8B\x13\xE8\x2A\x2A\x2A\x2A\x48\x8B\x5C\x24\x2A\x48\x83\xC4\x2A\x5F\xC3\xCC\xCC\xCC\xCC\x48\x89\x5C\x24" - "linux" "\x49\x8B\x54\x24\x2A\x45\x31\xC9\x45\x31\xC0\xC7\x45\x2A\x2A\x2A\x2A\x2A\x49\x8B\x34\x24\x48\x8D\x4D\x2A\x66\x0F\xEF\xC0\x48\xC7\x45\x2A\x2A\x2A\x2A\x2A\x48\x8D\xBB\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xF6\x45\x2A\x2A\x74\x2A\x48\x8B\x05\x2A\x2A\x2A\x2A\x48\x8B\x75\x2A\x48\x8B\x38\x48\x8B\x07\xFF\x50\x2A\x48\x83\xC4" - } - "CTakeDamageInfo" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x48\x89\x74\x24\x2A\x48\x89\x7C\x24\x2A\x41\x56\x48\x83\xEC\x2A\x45\x33\xF6\x48\xC7\x41" - "linux" "\x49\xBB\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x55\x48\x89\xE5\x48\x83\xEC\x2A\x4C\x8D\x15" - } - // "%sRecv usercmd %d. Margin:%5.1fms net +%2d queue =%5.1f total\n" - "ProcessUsercmds" - { - "library" "server" - "windows" "\x48\x8B\xC4\x44\x88\x48\x20\x44\x89\x40\x18\x48\x89\x50\x10\x53" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x2A\x89\x4D" - } - "CGamePlayerEquip_InputTriggerForAllPlayers" - { - "library" "server" - "windows" "\x40\x55\x53\x41\x54\x41\x56\x48\x8B\xEC\x48\x83\xEC\x2A\x4C\x8B\xF1" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xFD\x41\x54\x53\x48\x83\xEC\x2A\xE8\x2A\x2A\x2A\x2A\xC7\x45" - } - "CGamePlayerEquip_InputTriggerForActivatedPlayer" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x18\x56\x48\x83\xEC\x20\x48\x8B\x1A" - "linux" "\x55\x48\x89\xE5\x41\x56\x41\x55\x41\x54\x53\x48\x83\xEC\x2A\x48\x8B\x1E" - } - // Return value of this function is used to determine whether "NETWORK_DISCONNECT_REJECT_SERVERFULL to %s: Cannot get free client\n" gets printed - "GetFreeClient" - { - "library" "engine" - "windows" "\x48\x89\x54\x24\x2A\x53\x56\x57\x41\x56\x48\x83\xEC" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x49\x89\xFE\x41\x55\x41\x54\x49\x89\xF4\x53\x48\x81\xEC\x2A\x2A\x2A\x2A\x41\xC6\x01" - } - // The only function with "weapon_shield" and does fminf with 260.0 earlier - "CCSPlayerPawn_GetMaxSpeed" - { - "library" "server" - // Inlined by MSVC as of 2025-07-28 CS2 update - //"windows" "\x40\x53\x48\x83\xEC\x2A\x48\x8B\xD9\xE8\x2A\x2A\x2A\x2A\x84\xC0\x0F\x84\x2A\x2A\x2A\x2A\x48\x8B\x0D" - "linux" "\x55\x48\x89\xE5\x41\x55\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x2A\xE8\x2A\x2A\x2A\x2A\x84\xC0\x75\x2A\x48\x8D\x05" - } - // str: "Radial using: %s\n" - "FindUseEntity" - { - "library" "server" - "windows" "\x4C\x89\x44\x24\x2A\xF3\x0F\x11\x4C\x24\x2A\x55\x53\x56" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xFD\x41\x54\x48\x8D\x3D\x2A\x2A\x2A\x2A\x53\x48\x81\xEC" - } - "TraceFunc" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x48\x89\x74\x24\x2A\x48\x89\x7C\x24\x2A\x41\x54\x41\x56\x41\x57\x48\x81\xEC\x2A\x2A\x2A\x2A\x45\x33\xE4" - "linux" "\x48\xB8\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x55\x48\x89\xE5\x41\x55\x41\x54\x4C\x8D\x6F\x2A\x49\x89\xCC" - } - // str: "Physics/TraceShape (Server)" - "TraceShape" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x4C\x24\x2A\x55\x57" - "linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xCF\x41\x56\x49\x89\xF6\x41\x55\x4D\x89\xC5" - } - "CBasePlayerPawn_GetEyePosition" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x2A\x48\x8B\xF9\x48\x8B\xDA\x48\x8B\x89\x2A\x2A\x2A\x2A\x48\x85\xC9\x74\x2A\x48\x8B\x01" - "linux" "\x55\x48\x89\xE5\x53\x48\x89\xFB\x48\x83\xEC\x2A\x48\x8B\xBF\x2A\x2A\x2A\x2A\x48\x85\xFF\x0F\x84" - } - "CBasePlayerPawn_GetEyeAngles" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x57\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8B\xF9\x48\x8B\xDA\x48\x8B\x89\x2A\x2A\x2A\x2A\x48\x85\xC9" - "linux" "\x55\x48\x89\xE5\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x2A\x48\x8B\xBF\x2A\x2A\x2A\x2A\x48\x85\xFF\x0F\x84\x2A\x2A\x2A\x2A\x48\x8B\x07\x48\x8D\x15" - } - // Only ever referenced right next to string "TestActivator" - "CBaseFilter_InputTestActivator" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x2A\x4C\x8B\x02" - "linux" "\x55\x48\x89\xE5\x41\x54\x49\x89\xF4\x53\x48\x89\xFB\x48\x83\xEC\x2A\x48\x8B\x07\x48\x8B\x16" - } - // "Kicking user %s (sv_kick_players_with_cooldown=%d)\n" - "GameSystem_Think_CheckSteamBan" - { - "library" "server" - "windows" "\x41\x54\x48\x81\xEC\x2A\x2A\x2A\x2A\xBA\x2A\x2A\x2A\x2A\x48\x8D\x0D\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x48\x85\xC0" - "linux" "\x55\x48\x8D\x3D\x2A\x2A\x2A\x2A\xBE\x2A\x2A\x2A\x2A\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x48\x85\xC0\x0F\x84\x2A\x2A\x2A\x2A\x8B\x10" - } - // Location to CUtlMap unk that is referenced on Windows by function with "Notification about user penalty: %u/%u (%u sec)\n" string - // On Linux, a qword appears twice in GameSystem_Think_CheckSteamBan, and thrice in a sub-function of the function used for Windows (1 top, 2 bottom), the only other reference to this qword is some convar registration function with two unks above, sm_mapGcBanInformation is the unk further away - "CCSGameRules__sm_mapGcBanInformation" - { - "library" "server" - "windows" "\x48\x8D\x0D\x2A\x2A\x2A\x2A\x48\x89\x45\x2A\x0F\x11\x45" - "linux" "\x48\x8D\x0D\x2A\x2A\x2A\x2A\x48\x63\x51\x2A\x83\xFA\x2A\x0F\x84\x2A\x2A\x2A\x2A\xF7\x41\x2A\x2A\x2A\x2A\x2A\x74" - } - // Called right before "%d spawn groups:\n" - "GetSpawnGroups" - { - "library" "server" - "windows" "\x40\x56\x48\x83\xEC\x2A\x48\x89\x5C\x24\x2A\x48\x8D\xB1" - "linux" "\x55\x49\x89\xF1\xBE\x2A\x2A\x2A\x2A\x48\x89\xE5\x41\x57\x41\x56\x4C\x8D\xBF" - } - // Only has "weapon_incgrenade" and "weapon_incgrenade" strings - // May need to look into custom way of acquiring this function address, normal sig sees frequent breakage in the CS# project - "CCSPlayer_ItemServices_CanAcquire" - { - "library" "server" - "windows" "\x44\x89\x44\x24\x2A\x48\x89\x54\x24\x2A\x48\x89\x4C\x24\x2A\x55\x53\x56\x57\x41\x55\x41\x56\x41\x57\x48\x8B\xEC" - "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xCD\x41\x54\x49\x89\xFC\x53\x48\x89\xF3\x48\x83\xEC" - } - "CTriggerGravity_GravityTouch" - { - "library" "server" - "windows" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x2A\x48\x8B\x02\x48\x8B\xF9\x48\x8B\xCA\x48\x8B\xDA\xFF\x90\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\xF3\x0F\x10\x8F" - "linux" "\x48\x8B\x06\x55\x48\x89\xE5\x41\x54\x49\x89\xFC\x48\x89\xF7\x53\x48\x89\xF3\xFF\x90" - } - } - "Offsets" - { - "CBaseEntity::Precache" - { - "windows" "6" - "linux" "7" - } - "CBaseEntity::SetOwner" - { - "windows" "52" - "linux" "51" - } - // String: "%s<%i><%s><%s>" ChangeTeam() CTMDBG..." - "CCSPlayerController_ChangeTeam" - { - "windows" "102" - "linux" "101" - } - "GetHammerUniqueId" - { - "windows" "111" - "linux" "110" - } - "CBaseEntity::Use" - { - "windows" "144" - "linux" "143" - } - "CBaseEntity::StartTouch" - { - "windows" "147" - "linux" "146" - } - "CBaseEntity::Touch" - { - "windows" "148" - "linux" "147" - } - "CBaseEntity::EndTouch" - { - "windows" "149" - "linux" "148" - } - "Teleport" - { - "windows" "162" - "linux" "161" - } - // For these two, look for the names, you'll find vscript bindings - // Scroll down to where the var + 64 gets set to a function, that calls the offset we want - "IsPlayerPawn" - { - "windows" "168" - "linux" "167" - } - "IsPlayerController" - { - "windows" "169" - "linux" "168" - } - "CollisionRulesChanged" - { - "windows" "185" - "linux" "184" - } - "CCSPlayerController_Respawn" - { - "windows" "272" - "linux" "274" - } - // CBaseTrigger - "PassesTriggerFilters" - { - "windows" "266" - "linux" "267" - } - // Actually a bit of a wrapper function now? Eventually calls a long function with "player_hurt" in the middle and then inserts userid, health, priority, attacker strings - "CCSPlayerPawn::OnTakeDamage_Alive" - { - "windows" "249" - "linux" "250" - } - // Look for the kill command, go through its callback and you should a find call like this, with v9 being a pawn pointer: - // return (*(*v9 + 2976LL))(v9, v27, 0LL); - // 2976 (372 * 8) is the offset - "CBasePlayerPawn_CommitSuicide" - { - "windows" "400" - "linux" "400" - } - "GameEntitySystem" - { - "windows" "88" - "linux" "80" - } - // In the function with "[%03d] Found: %s, firing\n", you'll find a call into a pointer offset just a bit higher, that's the offset * 8 - "CGameRules_FindPickerEntity" - { - "windows" "25" - "linux" "26" - } - "CCSGameRules_GoToIntermission" - { - "windows" "128" - "linux" "129" - } - "CheckTransmitPlayerSlot" - { - "windows" "576" - "linux" "576" - } - // engine - // "tried to sprint to a non-client", there will be a check above like this: if ( a2 >= *(v5 + 632) ), note that this is a CUtlVector - "CNetworkGameServer_ClientList" - { - "windows" "74" - "linux" "74" - } - // Right above "mapgroup workshop;" string there is a virtual call to this on g_pGameTypes using "workshop" string - "IGameTypes_CreateWorkshopMapGroup" - { - "windows" "37" - "linux" "38" - } - // There's no easy way to find this, but it's a function that checks entity flags (0x370) and ends by calling RemoveFlag with 0x800000 (FL_BASEVELOCITY) - "CCSPlayer_MovementServices::CheckMovingGround" - { - "windows" "40" - "linux" "41" - } - "CCSPlayer_WeaponServices::DropWeapon" - { - "windows" "24" - "linux" "25" - } - "CCSPlayer_WeaponServices::SelectItem" - { - "windows" "26" - "linux" "27" - } - // server.dll -> xref 'sv_phys_stop_at_collision' first __fastcall - "CVPhys2World::GetTouchingList" - { - "windows" "121" - "linux" "121" - } - } - "Patches" - { - // Server - "ServerMovementUnlock" - { - "windows" "\xE9\xB0\x00\x00\x00\x90" - "linux" "\x90\x90\x90\x90\x90\x90" - } - "FixWaterFloorJump" - { - "windows" "\x11\x43" - "linux" "\x11\x43" - } - // Jumping over a check for nav mesh - "BotNavIgnore" - { - "windows" "\xE9\x2C\x00\x00\x00\x90" - "linux" "\xE9\x25\x00\x00\x00\x90" - } - // Make func_physbox pass itself as the caller in OnPlayerUse - // pCaller = inputdata->pCaller -> pCaller = this - // Windows: mov r8, [rbx+8] -> mov r8, rdi - // Linux: mov rdx, [r12+8] -> mov rdx, rbx - "CPhysBox_Use" - { - "windows" "\x49\x89\xF8\x90" - "linux" "\x48\x89\xDA\x90\x90" - } - } - } -} diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc new file mode 100644 index 000000000..b1fd950a6 --- /dev/null +++ b/gamedata/cs2fixes.jsonc @@ -0,0 +1,553 @@ +{ + "Signatures": + { + // Called from Host_Say + "UTIL_SayTextFilter": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 41 56 41 57 48 8D 6C 24 ? 48 81 EC ? ? ? ? 49 8B F8", + "linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 41 56 4C 8D 75 ? 41 55 41 89 CD 41 54 49 89 D4" + }, + // Called from Host_Say + "UTIL_SayText2Filter": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 41 56 41 57 48 8D 6C 24 ? 48 81 EC ? ? ? ? 45 0F B6 F0", + "linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 41 56 41 89 D6 31 D2" + }, + "IsHearingClient": + { + "library": "engine", + "windows": "40 53 48 83 EC ? 48 8B D9 3B 51", + "linux": "55 48 89 E5 41 56 41 55 41 54 53 48 89 FB 39 77" + }, + // idk a good way to find this again, i just brute forced the vtable. offset is 136 on CTriggerPush + "TriggerPush_Touch": + { + "library": "server", + "windows": "40 55 53 57 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B 02 48 8B F9", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 F5 41 54 53 48 89 FB 48 83 EC ? E8 ? ? ? ? 84 C0" + }, + // this is called in CTriggerPush::Touch, using IDA pseudocode look in an `if ( ( v & 0x80 ) != 0 )` and then `if ( v > 0.0 ) SetGroundEntity()` + "SetGroundEntity": + { + "library": "server", + "windows": "48 89 5C 24 ? 55 56 57 41 55 41 57 48 83 EC ? 44 8B 89", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 D5 41 54 49 89 F4 53 48 89 FB 48 83 EC ? 8B 87" + }, + // Check vauff's pin in #scripting + "ServerMovementUnlock": + { + "library": "server", + "windows": "0F 86 AF ? ? ? 0F 57 C0 0F 2E C2", + "linux": "0F 87 ? ? ? ? F3 0F 10 3D ? ? ? ? F3 0F 11 BD ? ? ? ? 48 89 DE" + }, + // String: "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam + "CCSPlayerController_SwitchTeam": + { + "library": "server", + "windows": "40 53 57 48 81 EC ? ? ? ? 48 8B D9 8B FA", + "linux": "55 48 89 E5 41 54 49 89 FC 89 F7" + }, + // String: "player_jump", then find 42C80000h or in pseudocode "*(a2 + 68) = 1120403456;", changing from 100 to 145 + "CheckJumpButtonWater": + { + "library": "server", + "windows": "C8 42 EB ? 4C 8B 77 ? 4D 39 6E", + "linux": "C8 42 41 C7 84 24 ? ? ? ? ? ? ? ? 41 C7 84 24 ? ? ? ? ? ? ? ? E9" + }, + // Called right after "Removed %s(%s)\n" + "UTIL_Remove": + { + "library": "server", + "windows": "48 85 C9 74 ? 48 8B D1 48 8B 0D ? ? ? ?", + "linux": "48 89 FE 48 85 FF 74 ? 48 8D 05 ? ? ? ? 48" + }, + // "SetPosition" is passed to this + "CEntitySystem_AddEntityIOEvent": + { + "library": "server", + "windows": "48 89 5C 24 18 4C 89 4C 24 20 48 89 4C 24 08 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 20", + "linux": "55 48 89 E5 41 55 49 89 CD 41 54 49 89 FC 53 BB" + }, + // "BombPlanted" is passed to this + "CEntityInstance_AcceptInput": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 49 8B F0 48 8B D9 48 8B 0D", + "linux": "55 48 89 F0 48 89 E5 41 57 49 89 FF 41 56 48 8D 7D" + }, + // Called by CEntityInstance_AcceptInput + "CEntityIdentity_AcceptInput": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 02", + "linux": "55 49 89 D3 48 89 E5 41 57 45 89 CF 41 56" + }, + // func_pushable inside CTriggerBrush::Use calls CEntityIOOutput::FireOutputInternal + // Windows - https://imgur.com/a/A3zcxQm + // Linux doesn't inline it so you need to find any of the xrefs and the proper function is right after it. + // You can tell it apart by the arguments: (a1 + 2616, v4, a1, &v6, 0.0); + "CEntityIOOutput_FireOutputInternal": + { + "library": "server", + "windows": "4C 89 4C 24 ? 48 89 4C 24 ? 53 56", + "linux": "55 48 89 E5 41 57 49 89 FF 41 56 41 55 41 54 49 89 D4 53 48 89 F3 48 83 EC ? 48 8D 05" + }, + // "multi_manager" is passed to this + "CGameEntitySystem_FindEntityByClassName": + { + "library": "server", + "windows": "48 83 EC 68 45 33 C9", + "linux": "55 45 31 C0 31 C9 48 89 E5 53 48 8D 5D ? 48 83 EC ? 48 89 DF" + }, + // "commentary_semaphore" is passed to this + "CGameEntitySystem_FindEntityByName": + { + "library": "server", + "windows": "48 81 EC 88 ? ? ? 4D 85 C0", + "linux": "55 48 89 E5 41 54 53 48 83 EC ? 48 85 D2" + }, + // "CBaseEntity::TakeDamageOld" + "CBaseEntity_TakeDamageOld": + { + "library": "server", + "windows": "40 55 41 54 41 55 41 56 41 57 48 81 EC ? ? ? ? 48 8D 6C 24 ? 48 89 9D ? ? ? ? 45 33 ED", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 41 54 49 89 F4 53 48 89 D3 48 83 EC ? 48 85 D2" + }, + // Should be xref'd right above "flGravity", takes a float arg + "CBaseEntity::SetGravityScale": + { + "library": "server", + "windows": "48 89 5C 24 ? 57 48 83 EC ? F3 0F 10 81 ? ? ? ? 48 8B F9 0F 29 74 24 ? 0F 28 F1 0F 2E C6 7A ? 74", + "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 81 EC ? ? ? ? 0F 2E 87 ? ? ? ? 7A ? 75 ? 48 81 C4 ? ? ? ? 5B 41 5C 41 5D 41 5E 41 5F 5D C3 0F 1F 40 ? 31 C9 31 F6 31 FF F3 0F 11 85 ? ? ? ? 66 89 8D ? ? ? ? BA ? ? ? ? B9 ? ? ? ? 66 0F EF C9 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 0F 29 8D ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? C7 85 ? ? ? ? ? ? ? ? E8 ? ? ? ? F3 0F 10 85 ? ? ? ? 85 C0 41 89 C4 0F 8E ? ? ? ? 48 63 8D ? ? ? ? 48 63 D0 31 F6 F3 0F 11 85 ? ? ? ? 48 C1 E2 ? 48 8B BD ? ? ? ? 48 C1 E1 ? 81 BD ? ? ? ? ? ? ? ? 40 0F 96 C6 E8 ? ? ? ? 8B 95 ? ? ? ? F3 0F 10 85 ? ? ? ? 48 89 85 ? ? ? ? 81 FA ? ? ? ? 0F 87" + }, + // "Game System %s is defined twice!\n" + // Note that this signature points to the instruction with sm_pFirst which is the first qword referenced in the function. + "IGameSystem_InitAllSystems_pFirst": + { + "library": "server", + "windows": "48 8B 1D ? ? ? ? 48 85 DB 0F 84 ? ? ? ? BD", + "linux": "4C 8B 35 ? ? ? ? 4D 85 F6 75 ? E9" + }, + // Windows "%s: IGameSystem::LoopPostInitAllSystems(start)\n" + // Linux "%s: IGameSystem::LoopInitAllSystems(start)" + // In windows it's the only qword that gets nullchecked, while in linux it gets set to another qword's address + "IGameSystem_LoopPostInitAllSystems_pEventDispatcher": + { + "library": "server", + "windows": "48 39 1D ? ? ? ? 74 ? 39 05", + "linux": "4C 8B 25 ? ? ? ? 48 8B 05 ? ? ? ? 8B 35" + }, + // "--CLoopModeGame::SetWorldSession" + // In the above, a number is checked if > 0 then the function is called + "IGameSystem_LoopDestroyAllSystems_s_GameSystems": + { + "library": "server", + "windows": "8B 05 ? ? ? ? 83 E8 ? 48 63 F8 0F 88", + "linux": "8B 05 ? ? ? ? 89 C2 83 EA ? 0F 88 ? ? ? ? 4C 8D 3D" + }, + "CBasePlayerController_SetPawn": + { + "library": "server", + "windows": "44 88 4C 24 ? 53 57 41 54 41 56 41 57 48 83 EC", + "linux": "55 48 8D 87 ? ? ? ? 48 89 E5 41 57 41 89 CF" + }, + // String: "CNavMesh::GetNearestNavArea" + "CNavMesh_GetNearestNavArea": + { + "library": "server", + "windows": "48 89 5C 24 ? 44 89 4C 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24", + "linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 41 56 49 89 FE 41 55 48 8D 3D" + }, + // Search "Changes's player's model", look for a function containing 'models/%s.vmdl'. Below V_snprintf is the one + // This matches 2 functions, however they're literally identical + "CBaseModelEntity_SetModel": + { + "library": "server", + "windows": "40 53 48 83 EC ? 48 8B D9 4C 8B C2 48 8B 0D ? ? ? ? 48 8D 54 24 ? 48 8B 01 FF 50 ? 48 8B 44 24", + "linux": "55 48 89 F2 48 89 E5 53 48 89 FB 48 8D 7D ? 48 83 EC ? 48 8D 05 ? ? ? ? 48 8B 30 48 8B 06" + }, + "CGameRules_TerminateRound": + { + "library": "server", + "windows": "48 8B C4 4C 89 48 ? 48 89 48 ? 55 56 41 56", + "linux": "55 48 89 E5 41 57 49 89 FF 41 56 41 55 41 54 53 48 81 EC ? ? ? ? 48 8D 05 ? ? ? ? F3 0F 11 85" + }, + "CCSPlayer_WeaponServices_CanUse": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 83 EC ? 48 8B 01 48 8B FA", + "linux": "55 48 8D 15 ? ? ? ? 48 89 E5 41 55 41 54 49 89 FC 53 48 89 F3 48 83 EC ? 48 8B 07 48 8B 80" + }, + "CCSPlayer_WeaponServices_EquipWeapon": + { + "library": "server", + "windows": "48 89 5C 24 ? 57 48 83 EC ? 48 83 79 ? ? 48 8B FA 48 8B D9 75 ? E8 ? ? ? ? 48 8B 53", + "linux": "55 48 89 E5 41 55 41 54 49 89 FC 53 48 89 F3 48 83 EC ? 48 8B 77" + }, + "CreateEntityByName": + { + "library": "server", + "windows": "48 83 EC 48 C6 44 24 30 00", + "linux": "48 8D 05 ? ? ? ? 55 48 89 FA" + }, + "DispatchSpawn": + { + "library": "server", + "windows": "48 89 5C 24 10 57 48 83 EC 30 48 8B DA 48 8B F9 48 85 C9", + "linux": "48 85 FF 74 ? 55 48 89 E5 41 55 49 89 FD" + }, + // Look for "SetEntityName", that will be the vscript binding definition + // Scroll a bit down and you'll find something like this (note the offset): *(_QWORD *)(v453 + 64) = sub_1807B0350; + // that function is just a jump to the one we want + "CEntityIdentity_SetEntityName": + { + "library": "server", + "windows": "48 89 5C 24 10 57 48 83 EC 20 48 8B D9 4C 8B C2", + "linux": "55 48 89 F2 48 89 E5 41 55 41 54 53" + }, + // "Error - cannot add bots after game is over." + "BotNavIgnore": + { + "library": "server", + "windows": "0F 84 ? ? ? ? 80 B8 ? ? ? ? 00 0F 84 ? ? ? ? 80 3D ? ? ? ? 00 74 15", + "linux": "0F 84 ? ? ? ? 44 0F B6 B0 ? ? ? ? 45 84 F6 0F 84" + }, + // next to "soundname", in windows it's the last referenced sub while in linux it's right after + // this is a vscript binding though so it may be removed in the future? + "CBaseEntity_EmitSoundParams": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 48 8B EC 48 81 EC ? ? ? ? 33 C0", + "linux": "48 B8 ? ? ? ? ? ? ? ? 55 0F 28 D0" + }, + // "ParticleEffect", found in a function with 9 arguments + "DispatchParticleEffect": + { + "library": "server", + "windows": "48 89 5C 24 08 48 89 74 24 10 48 89 7C 24 18 4C 89 74 24 20 55 48 8D 6C 24 D1", + "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 41 89 CC 53 48 89 D3" + }, + // search for "land_%s", this is called after that string is referenced (the one with 4 parameters). + // (function that calls it also contains "T_Default.SuitLand"). + "CBaseEntity_EmitSoundFilter": + { + "library": "server", + "windows": "40 53 48 83 EC ? 4C 89 4C 24 ? 48 8B D9 45 8B C8", + "linux": "55 48 89 E5 53 48 89 FB 48 83 EC ? E8 ? ? ? ? 48 89 D8 48 8B 5D ? C9 C3 CC CC CC CC CC CC 48 B8" + }, + // "PlayerMovementTraces" + "ProcessMovement": + { + "library": "server", + "windows": "40 57 41 57 48 81 EC ? ? ? ? 48 83 79", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 F5 41 54 53 48 89 FB 48 83 EC ? 48 8B 7F" + }, + // "env_shake %s with", in either xref there will be a call to SetMoveType(a1, 0, 0) at the top + "CBaseEntity_SetMoveType": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 41 0F B6 F0", + "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 41 89 D4 53 48 89 FB 48 81 EC ? ? ? ? 40 38 B7" + }, + // Use CBaseEntity::Use offset + // This signature points directly to the instruction to patch + "CPhysBox_Use": + { + "library": "server", + "windows": "4C 8B 43 ? 48 8D 8F ? ? ? ? 48 8B 13 E8 ? ? ? ? 48 8B 5C 24 ? 48 83 C4 ? 5F C3 CC CC CC CC 48 89 5C 24", + "linux": "49 8B 54 24 ? 45 31 C9 45 31 C0 C7 45 ? ? ? ? ? 49 8B 34 24 48 8D 4D ? 66 0F EF C0 48 C7 45 ? ? ? ? ? 48 8D BB ? ? ? ? E8 ? ? ? ? F6 45 ? ? 74 ? 48 8B 05 ? ? ? ? 48 8B 75 ? 48 8B 38 48 8B 07 FF 50 ? 48 83 C4" + }, + "CTakeDamageInfo": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 45 33 F6 48 C7 41", + "linux": "49 BB ? ? ? ? ? ? ? ? 55 48 89 E5 48 83 EC ? 4C 8D 15" + }, + // "%sRecv usercmd %d. Margin:%5.1fms net +%2d queue =%5.1f total\n" + "ProcessUsercmds": + { + "library": "server", + "windows": "48 8B C4 44 88 48 20 44 89 40 18 48 89 50 10 53", + "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 83 EC ? 89 4D" + }, + "CGamePlayerEquip_InputTriggerForAllPlayers": + { + "library": "server", + "windows": "40 55 53 41 54 41 56 48 8B EC 48 83 EC ? 4C 8B F1", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 41 54 53 48 83 EC ? E8 ? ? ? ? C7 45" + }, + "CGamePlayerEquip_InputTriggerForActivatedPlayer": + { + "library": "server", + "windows": "48 89 5C 24 18 56 48 83 EC 20 48 8B 1A", + "linux": "55 48 89 E5 41 56 41 55 41 54 53 48 83 EC ? 48 8B 1E" + }, + // Return value of this function is used to determine whether "NETWORK_DISCONNECT_REJECT_SERVERFULL to %s: Cannot get free client\n" gets printed + "GetFreeClient": + { + "library": "engine", + "windows": "48 89 54 24 ? 53 56 57 41 56 48 83 EC", + "linux": "55 48 89 E5 41 57 41 56 49 89 FE 41 55 41 54 49 89 F4 53 48 81 EC ? ? ? ? 41 C6 01" + }, + // The only function with "weapon_shield" and does fminf with 260.0 earlier + "CCSPlayerPawn_GetMaxSpeed": + { + "library": "server", + // Inlined by MSVC as of 2025-07-28 CS2 update + //"windows": "40 53 48 83 EC ? 48 8B D9 E8 ? ? ? ? 84 C0 0F 84 ? ? ? ? 48 8B 0D", + "linux": "55 48 89 E5 41 55 41 54 53 48 89 FB 48 83 EC ? E8 ? ? ? ? 84 C0 75 ? 48 8D 05" + }, + // str: "Radial using: %s\n" + "FindUseEntity": + { + "library": "server", + "windows": "4C 89 44 24 ? F3 0F 11 4C 24 ? 55 53 56", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 41 54 48 8D 3D ? ? ? ? 53 48 81 EC" + }, + "TraceFunc": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 54 41 56 41 57 48 81 EC ? ? ? ? 45 33 E4", + "linux": "48 B8 ? ? ? ? ? ? ? ? 55 48 89 E5 41 55 41 54 4C 8D 6F ? 49 89 CC" + }, + // str: "Physics/TraceShape (Server)" + "TraceShape": + { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 4C 24 ? 55 57", + "linux": "55 48 89 E5 41 57 49 89 CF 41 56 49 89 F6 41 55 4D 89 C5" + }, + "CBasePlayerPawn_GetEyePosition": + { + "library": "server", + "windows": "48 89 5C 24 ? 57 48 83 EC ? 48 8B F9 48 8B DA 48 8B 89 ? ? ? ? 48 85 C9 74 ? 48 8B 01", + "linux": "55 48 89 E5 53 48 89 FB 48 83 EC ? 48 8B BF ? ? ? ? 48 85 FF 0F 84" + }, + "CBasePlayerPawn_GetEyeAngles": + { + "library": "server", + "windows": "48 89 5C 24 ? 57 48 81 EC ? ? ? ? 48 8B F9 48 8B DA 48 8B 89 ? ? ? ? 48 85 C9", + "linux": "55 48 89 E5 41 54 53 48 89 FB 48 83 EC ? 48 8B BF ? ? ? ? 48 85 FF 0F 84 ? ? ? ? 48 8B 07 48 8D 15" + }, + // Only ever referenced right next to string "TestActivator" + "CBaseFilter_InputTestActivator": + { + "library": "server", + "windows": "48 89 5C 24 ? 57 48 83 EC ? 4C 8B 02", + "linux": "55 48 89 E5 41 54 49 89 F4 53 48 89 FB 48 83 EC ? 48 8B 07 48 8B 16" + }, + // "Kicking user %s (sv_kick_players_with_cooldown=%d)\n" + "GameSystem_Think_CheckSteamBan": + { + "library": "server", + "windows": "41 54 48 81 EC ? ? ? ? BA ? ? ? ? 48 8D 0D ? ? ? ? E8 ? ? ? ? 48 85 C0", + "linux": "55 48 8D 3D ? ? ? ? BE ? ? ? ? 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC ? ? ? ? E8 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 8B 10" + }, + // Location to CUtlMap unk that is referenced on Windows by function with "Notification about user penalty: %u/%u (%u sec)\n" string + // On Linux, a qword appears twice in GameSystem_Think_CheckSteamBan, and thrice in a sub-function of the function used for Windows (1 top, 2 bottom), the only other reference to this qword is some convar registration function with two unks above, sm_mapGcBanInformation is the unk further away + "CCSGameRules__sm_mapGcBanInformation": + { + "library": "server", + "windows": "48 8D 0D ? ? ? ? 48 89 45 ? 0F 11 45", + "linux": "48 8D 0D ? ? ? ? 48 63 51 ? 83 FA ? 0F 84 ? ? ? ? F7 41 ? ? ? ? ? 74" + }, + // Called right before "%d spawn groups:\n" + "GetSpawnGroups": + { + "library": "server", + "windows": "40 56 48 83 EC ? 48 89 5C 24 ? 48 8D B1", + "linux": "55 49 89 F1 BE ? ? ? ? 48 89 E5 41 57 41 56 4C 8D BF" + }, + // Only has "weapon_incgrenade" and "weapon_incgrenade" strings + // May need to look into custom way of acquiring this function address, normal sig sees frequent breakage in the CS# project + "CCSPlayer_ItemServices_CanAcquire": + { + "library": "server", + "windows": "44 89 44 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 53 56 57 41 55 41 56 41 57 48 8B EC", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 CD 41 54 49 89 FC 53 48 89 F3 48 83 EC" + }, + "CTriggerGravity_GravityTouch": + { + "library": "server", + "windows": "48 89 5C 24 ? 57 48 83 EC ? 48 8B 02 48 8B F9 48 8B CA 48 8B DA FF 90 ? ? ? ? 84 C0 74 ? F3 0F 10 8F", + "linux": "48 8B 06 55 48 89 E5 41 54 49 89 FC 48 89 F7 53 48 89 F3 FF 90" + } + }, + "Offsets": + { + "CBaseEntity::Precache": + { + "windows": 6, + "linux": 7 + }, + "CBaseEntity::SetOwner": + { + "windows": 52, + "linux": 51 + }, + // String: "%s<%i><%s><%s>" ChangeTeam() CTMDBG..." + "CCSPlayerController_ChangeTeam": + { + "windows": 102, + "linux": 101 + }, + "GetHammerUniqueId": + { + "windows": 111, + "linux": 110 + }, + "CBaseEntity::Use": + { + "windows": 144, + "linux": 143 + }, + "CBaseEntity::StartTouch": + { + "windows": 147, + "linux": 146 + }, + "CBaseEntity::Touch": + { + "windows": 148, + "linux": 147 + }, + "CBaseEntity::EndTouch": + { + "windows": 149, + "linux": 148 + }, + "Teleport": + { + "windows": 162, + "linux": 161 + }, + // For these two, look for the names, you'll find vscript bindings + // Scroll down to where the var + 64 gets set to a function, that calls the offset we want + "IsPlayerPawn": + { + "windows": 168, + "linux": 167 + }, + "IsPlayerController": + { + "windows": 169, + "linux": 168 + }, + "CollisionRulesChanged": + { + "windows": 185, + "linux": 184 + }, + "CCSPlayerController_Respawn": + { + "windows": 272, + "linux": 274 + }, + // CBaseTrigger + "PassesTriggerFilters": + { + "windows": 266, + "linux": 267 + }, + // Actually a bit of a wrapper function now? Eventually calls a long function with "player_hurt" in the middle and then inserts userid, health, priority, attacker strings + "CCSPlayerPawn::OnTakeDamage_Alive": + { + "windows": 249, + "linux": 250 + }, + // Look for the kill command, go through its callback and you should a find call like this, with v9 being a pawn pointer: + // return (*(*v9 + 2976LL))(v9, v27, 0LL); + // 2976 (372 * 8) is the offset + "CBasePlayerPawn_CommitSuicide": + { + "windows": 400, + "linux": 400 + }, + "GameEntitySystem": + { + "windows": 88, + "linux": 80 + }, + // In the function with "[%03d] Found: %s, firing\n", you'll find a call into a pointer offset just a bit higher, that's the offset * 8 + "CGameRules_FindPickerEntity": + { + "windows": 25, + "linux": 26 + }, + "CCSGameRules_GoToIntermission": + { + "windows": 128, + "linux": 129 + }, + "CheckTransmitPlayerSlot": + { + "windows": 576, + "linux": 576 + }, + // engine + // "tried to sprint to a non-client", there will be a check above like this: if ( a2 >= *(v5 + 632) ), note that this is a CUtlVector + "CNetworkGameServer_ClientList": + { + "windows": 74, + "linux": 74 + }, + // Right above "mapgroup workshop;" string there is a virtual call to this on g_pGameTypes using "workshop" string + "IGameTypes_CreateWorkshopMapGroup": + { + "windows": 37, + "linux": 38 + }, + // There's no easy way to find this, but it's a function that checks entity flags (0x370) and ends by calling RemoveFlag with 0x800000 (FL_BASEVELOCITY) + "CCSPlayer_MovementServices::CheckMovingGround": + { + "windows": 40, + "linux": 41 + }, + "CCSPlayer_WeaponServices::DropWeapon": + { + "windows": 24, + "linux": 25 + }, + "CCSPlayer_WeaponServices::SelectItem": + { + "windows": 26, + "linux": 27 + }, + // server.dll -> xref 'sv_phys_stop_at_collision' first __fastcall + "CVPhys2World::GetTouchingList": + { + "windows": 121, + "linux": 121 + } + }, + "Patches": + { + "ServerMovementUnlock": + { + "windows": "E9 B0 00 00 00 90", + "linux": "90 90 90 90 90 90" + }, + "FixWaterFloorJump": + { + "windows": "11 43", + "linux": "11 43" + }, + // Jumping over a check for nav mesh + "BotNavIgnore": + { + "windows": "E9 2C 00 00 00 90", + "linux": "E9 25 00 00 00 90" + }, + // Make func_physbox pass itself as the caller in OnPlayerUse + // pCaller = inputdata->pCaller -> pCaller = this + // Windows: mov r8, [rbx+8] -> mov r8, rdi + // Linux: mov rdx, [r12+8] -> mov rdx, rbx + "CPhysBox_Use": + { + "windows": "49 89 F8 90", + "linux": "48 89 DA 90 90" + } + } +} diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 7aac86333..681770f12 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -165,19 +165,12 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool Message("Starting plugin.\n"); - CBufferStringGrowable<256> gamedirpath; - g_pEngineServer2->GetGameDir(gamedirpath); - - std::string gamedirname = CGameConfig::GetDirectoryName(gamedirpath.Get()); - - const char* gamedataPath = "addons/cs2fixes/gamedata/cs2fixes.games.txt"; - Message("Loading %s for game: %s\n", gamedataPath, gamedirname.c_str()); - - g_GameConfig = new CGameConfig(gamedirname, gamedataPath); + g_GameConfig = new CGameConfig(); char conf_error[255] = ""; - if (!g_GameConfig->Init(g_pFullFileSystem, conf_error, sizeof(conf_error))) + + if (!g_GameConfig->Init(conf_error, sizeof(conf_error))) { - snprintf(error, maxlen, "Could not read %s: %s", g_GameConfig->GetPath().c_str(), conf_error); + snprintf(error, maxlen, "%s", conf_error); Panic("%s\n", error); return false; } @@ -1318,4 +1311,4 @@ bool CS2Fixes::Pause(char* error, size_t maxlen) bool CS2Fixes::Unpause(char* error, size_t maxlen) { return true; -} \ No newline at end of file +} diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index 458a3f7bd..ceab26717 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -1,76 +1,111 @@ #include "gameconfig.h" #include "addresses.h" +#undef snprintf +#include "vendor/nlohmann/json.hpp" -CGameConfig* g_GameConfig = nullptr; +#include +#include -CGameConfig::CGameConfig(const std::string& gameDir, const std::string& path) -{ - this->m_szGameDir = gameDir; - this->m_szPath = path; - this->m_pKeyValues = new KeyValues("Games"); -} +CGameConfig* g_GameConfig = nullptr; -CGameConfig::~CGameConfig() +bool CGameConfig::Init(char* conf_error, int conf_error_size) { - delete m_pKeyValues; -} + const char* pszGamedataPath = "addons/cs2fixes/gamedata/cs2fixes.jsonc"; + char szPath[MAX_PATH]; + V_snprintf(szPath, sizeof(szPath), "%s%s%s", Plat_GetGameDirectory(), "/csgo/", pszGamedataPath); + std::ifstream gamedataFile(szPath); -bool CGameConfig::Init(IFileSystem* filesystem, char* conf_error, int conf_error_size) -{ - if (!m_pKeyValues->LoadFromFile(filesystem, m_szPath.c_str(), nullptr)) + if (!gamedataFile.is_open()) { - snprintf(conf_error, conf_error_size, "Failed to load gamedata file"); + snprintf(conf_error, conf_error_size, "Failed to open %s, gamedata not loaded", pszGamedataPath); return false; } - KeyValues* game = m_pKeyValues->FindKey(m_szGameDir.c_str(), false); - if (game) + ordered_json jsonGamedata = ordered_json::parse(gamedataFile, nullptr, false, true); + + if (jsonGamedata.is_discarded() || !jsonGamedata.is_object()) { + snprintf(conf_error, conf_error_size, "Failed parsing gamedata JSON from %s", pszGamedataPath); + return false; + } + #if defined _LINUX - const char* platform = "linux"; + const char* platform = "linux"; #else - const char* platform = "windows"; + const char* platform = "windows"; #endif - KeyValues* offsets = game->FindKey("Offsets", false); - if (offsets) + for (auto& [strSection, jsonSection] : jsonGamedata.items()) + { + if (!jsonSection.is_object()) { - FOR_EACH_SUBKEY(offsets, it) - { - m_umOffsets[it->GetName()] = it->GetInt(platform, -1); - } + snprintf(conf_error, conf_error_size, "Section '%s' must be an object", strSection.c_str()); + return false; } - KeyValues* signatures = game->FindKey("Signatures", false); - if (signatures) + for (auto& [strEntry, jsonEntry] : jsonSection.items()) { - FOR_EACH_SUBKEY(signatures, it) + if (!jsonEntry.is_object()) { - m_umLibraries[it->GetName()] = std::string(it->GetString("library")); - m_umSignatures[it->GetName()] = std::string(it->GetString(platform)); + snprintf(conf_error, conf_error_size, "Entry '%s' must be an object", strEntry.c_str()); + return false; } - } - KeyValues* patches = game->FindKey("Patches", false); - if (patches) - { - FOR_EACH_SUBKEY(patches, it) + if (strSection == "Offsets") + { + const auto platformOffset = jsonEntry.find(platform); + if (platformOffset == jsonEntry.end()) + continue; + + if (!platformOffset->is_number_integer()) + { + snprintf(conf_error, conf_error_size, "Offset '%s' '%s' value is not numeric", strEntry.c_str(), platform); + return false; + } + + m_umOffsets[strEntry] = platformOffset->get(); + } + else if (strSection == "Signatures") + { + const auto library = jsonEntry.find("library"); + if (library == jsonEntry.end() || !library->is_string()) + { + snprintf(conf_error, conf_error_size, "Signature '%s' is missing string 'library' value", strEntry.c_str()); + return false; + } + + m_umLibraries[strEntry] = library->get(); + + const auto platformValue = jsonEntry.find(platform); + if (platformValue == jsonEntry.end()) + continue; + + if (!platformValue->is_string()) + { + snprintf(conf_error, conf_error_size, "Signature '%s' '%s' value is not a string", strEntry.c_str(), platform); + return false; + } + + m_umSignatures[strEntry] = platformValue->get(); + } + else if (strSection == "Patches") { - m_umPatches[it->GetName()] = std::string(it->GetString(platform)); + const auto platformValue = jsonEntry.find(platform); + if (platformValue == jsonEntry.end()) + continue; + + if (!platformValue->is_string()) + { + snprintf(conf_error, conf_error_size, "Patch '%s' '%s' value is not a string", strEntry.c_str(), platform); + return false; + } + + m_umPatches[strEntry] = platformValue->get(); } } } - else - { - snprintf(conf_error, conf_error_size, "Failed to find game: %s", m_szGameDir.c_str()); - return false; - } - return true; -} -const std::string CGameConfig::GetPath() -{ - return m_szPath; + return true; } const char* CGameConfig::GetSignature(const std::string& name) @@ -185,7 +220,7 @@ void* CGameConfig::ResolveSignature(const char* name) } size_t iLength = 0; - byte* pSignature = HexToByte(signature, iLength); + byte* pSignature = IDASigToUint8Array(signature, iLength); if (!pSignature) return nullptr; @@ -205,61 +240,73 @@ void* CGameConfig::ResolveSignature(const char* name) return address; } -// Static functions -std::string CGameConfig::GetDirectoryName(const std::string& directoryPathInput) +int CGameConfig::ParseHexNibble(char c) { - std::string directoryPath = std::string(directoryPathInput); + if (c >= '0' && c <= '9') + return c - '0'; + + const char lower = static_cast(std::tolower(static_cast(c))); + if (lower >= 'a' && lower <= 'f') + return lower - 'a' + 10; - size_t found = std::string(directoryPath).find_last_of("/\\"); - if (found != std::string::npos) - return std::string(directoryPath, found + 1); - return ""; + return -1; } -int CGameConfig::HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes) +bool CGameConfig::ParsePatternBytes(const char* pattern, std::vector& bytes) { - if (!hexString) - { - printf("Invalid hex string.\n"); - return -1; - } - - size_t hexStringLength = strlen(hexString); - size_t byteCount = hexStringLength / 4; // Each "\\x" represents one byte. + if (!pattern) + return false; - if (hexStringLength % 4 != 0 || byteCount == 0 || byteCount > maxBytes) + const char* cursor = pattern; + while (*cursor) { - printf("Invalid hex string format or byte count.\n"); - return -1; // Return an error code. - } + while (*cursor && std::isspace(static_cast(*cursor))) + cursor++; - for (size_t i = 0; i < hexStringLength; i += 4) - { - if (sscanf(hexString + i, "\\x%2hhX", &byteArray[i / 4]) != 1) + if (!*cursor) + break; + + if (*cursor == '?') { - printf("Failed to parse hex string at position %zu.\n", i); - return -1; // Return an error code. + bytes.push_back('\x2A'); + cursor++; + if (*cursor == '?') + cursor++; + continue; } + + const int highNibble = ParseHexNibble(cursor[0]); + const int lowNibble = ParseHexNibble(cursor[1]); + if (highNibble < 0 || lowNibble < 0) + return false; + + bytes.push_back(static_cast((highNibble << 4) | lowNibble)); + cursor += 2; } - return byteCount; // Return the number of bytes successfully converted. + return !bytes.empty(); } -byte* CGameConfig::HexToByte(const char* src, size_t& length) +byte* CGameConfig::IDASigToUint8Array(const char* signature, size_t& length) { - if (!src || strlen(src) <= 0) + if (!signature || strlen(signature) <= 0) { - Panic("Invalid hex string\n"); + Panic("Invalid IDA signature string\n"); return nullptr; } - length = strlen(src) / 4; - uint8_t* dest = new uint8_t[length]; - int byteCount = HexStringToUint8Array(src, dest, length); - if (byteCount <= 0) + std::vector bytes; + if (!ParsePatternBytes(signature, bytes)) { - Panic("Invalid hex format %s\n", src); + Panic("Invalid IDA signature format \"%s\"\n", signature); return nullptr; } + + length = bytes.size(); + uint8_t* dest = new uint8_t[length]; + + for (size_t i = 0; i < length; i++) + dest[i] = bytes[i]; + return (byte*)dest; } diff --git a/src/gameconfig.h b/src/gameconfig.h index 479920fbb..9a296902f 100644 --- a/src/gameconfig.h +++ b/src/gameconfig.h @@ -1,21 +1,21 @@ #pragma once -#include "KeyValues.h" +#undef snprintf +#include "vendor/nlohmann/json_fwd.hpp" +#include "wchartypes.h" #include #include #include +#include class CModule; +using ordered_json = nlohmann::ordered_json; class CGameConfig { public: - CGameConfig(const std::string& gameDir, const std::string& path); - ~CGameConfig(); - - bool Init(IFileSystem* filesystem, char* conf_error, int conf_error_size); - const std::string GetPath(); + bool Init(char* conf_error, int conf_error_size); const char* GetLibrary(const std::string& name); const char* GetSignature(const std::string& name); const char* GetSymbol(const char* name); @@ -25,14 +25,11 @@ class CGameConfig CModule** GetModule(const char* name); bool IsSymbol(const char* name); void* ResolveSignature(const char* name); - static std::string GetDirectoryName(const std::string& directoryPathInput); - static int HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes); - static byte* HexToByte(const char* src, size_t& length); + int ParseHexNibble(char c); + bool ParsePatternBytes(const char* pattern, std::vector& bytes); + byte* IDASigToUint8Array(const char* signature, size_t& length); private: - std::string m_szGameDir; - std::string m_szPath; - KeyValues* m_pKeyValues; std::unordered_map m_umOffsets; std::unordered_map m_umSignatures; std::unordered_map m_umAddresses; diff --git a/src/mempatch.cpp b/src/mempatch.cpp index 3500aa885..0cec70b55 100644 --- a/src/mempatch.cpp +++ b/src/mempatch.cpp @@ -46,7 +46,7 @@ bool CMemPatch::PerformPatch(CGameConfig* gameConfig) Panic("Failed to find patch for %s\n", m_pszName); return false; } - m_pPatch = gameConfig->HexToByte(patch, m_iPatchLength); + m_pPatch = gameConfig->IDASigToUint8Array(patch, m_iPatchLength); if (!m_pPatch) return false; From 650f1b197ade8f68df90903266aba8c42b2f93c8 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 27 Mar 2026 01:05:33 -0400 Subject: [PATCH 02/32] Add AGENTS.md --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..9de14e551 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +- For compilation tests, run `docker compose up` in the project directory \ No newline at end of file From 494d4a17eabdf727238f5730f6d0007221371a46 Mon Sep 17 00:00:00 2001 From: tilgep Date: Mon, 20 Apr 2026 23:34:17 +0100 Subject: [PATCH 03/32] Strip trailing space from player names (#436) * Strip trailing space from player names * Remove trailing space check in player targetting --- src/cs2_sdk/entity/cbaseplayercontroller.h | 14 +++++++++++++- src/cs2_sdk/entity/ccsplayercontroller.h | 2 +- src/detours.cpp | 2 +- src/playermanager.cpp | 8 +------- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/cs2_sdk/entity/cbaseplayercontroller.h b/src/cs2_sdk/entity/cbaseplayercontroller.h index 4aa2de7b8..621e016f9 100644 --- a/src/cs2_sdk/entity/cbaseplayercontroller.h +++ b/src/cs2_sdk/entity/cbaseplayercontroller.h @@ -51,7 +51,19 @@ class CBasePlayerController : public CBaseEntity // - An observer pawn if spectating // - A bot pawn if controlling one CBasePlayerPawn* GetPawn() { return m_hPawn.Get(); } - const char* GetPlayerName() { return m_iszPlayerName(); } + const char* GetPlayerName() + { + static char buf[128]; + const char* name = m_iszPlayerName(); + strncpy(buf, name, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == ' ') + buf[len - 1] = '\0'; + + return buf; + } int GetPlayerSlot() { return entindex() - 1; } bool IsConnected() { return m_iConnected() == PlayerConnectedState::PlayerConnected; } void SetPawn(CCSPlayerPawn* pawn) diff --git a/src/cs2_sdk/entity/ccsplayercontroller.h b/src/cs2_sdk/entity/ccsplayercontroller.h index a53eaad09..cc994b9d9 100644 --- a/src/cs2_sdk/entity/ccsplayercontroller.h +++ b/src/cs2_sdk/entity/ccsplayercontroller.h @@ -157,7 +157,7 @@ class CCSPlayerController : public CBasePlayerController m_szClan = g_pEntitySystem->AllocPooledString(pszClanTag); // This name swap trick is necessary to get clients to display the new clan tag - std::string strName = GetPlayerName(); + std::string strName = m_iszPlayerName(); if (!strName.empty() && strName.back() == ' ') strName.pop_back(); diff --git a/src/detours.cpp b/src/detours.cpp index 89c52f0bd..534afdc53 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -386,7 +386,7 @@ void FASTCALL Detour_UTIL_SayText2Filter( Message("Chat from %s to %s: %s\n", param1, target->GetPlayerName(), param2); #endif - UTIL_SayText2Filter(filter, pEntity, eMessageType, msg_name, param1, param2, param3, param4); + UTIL_SayText2Filter(filter, pEntity, eMessageType, msg_name, pEntity->GetPlayerName(), param2, param3, param4); } bool FASTCALL Detour_CCSPlayer_WeaponServices_CanUse(CCSPlayer_WeaponServices* pWeaponServices, CBasePlayerWeapon* pPlayerWeapon) diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 9fc7214d9..3fd08da14 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -1590,13 +1590,7 @@ ETargetError CPlayerManager::GetPlayersFromString(CCSPlayerController* pPlayer, if (!pTarget || !pTarget->IsController() || !pTarget->IsConnected() || pTarget->m_bIsHLTV) continue; - std::string strName = pTarget->GetPlayerName(); - - // Ignore space that might be added by clan tag name swap trick - if (!strName.empty() && strName.back() == ' ') - strName.pop_back(); - - if ((!bExactName && V_stristr(strName.c_str(), pszTarget)) || !V_strcmp(strName.c_str(), pszTarget)) + if ((!bExactName && V_stristr(pTarget->GetPlayerName(), pszTarget)) || !V_strcmp(pTarget->GetPlayerName(), pszTarget)) { nType = ETargetType::PLAYER; if (iNumClients == 1) From 68fa26395358e1f938acaf8de25e1000f18bcb2e Mon Sep 17 00:00:00 2001 From: AcaroMan <82720436+AcaroMan@users.noreply.github.com> Date: Mon, 20 Apr 2026 23:54:02 +0100 Subject: [PATCH 04/32] zr_infect_min_count_req (#435) * zr_infect_min_count_req * Undo renaming and removed redundant validation * Readded comment * Fix PR * Simplify --------- Co-authored-by: Acaro Co-authored-by: Vauff --- cfg/cs2fixes/cs2fixes.cfg | 1 + src/zombiereborn.cpp | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 39ea5e3ef..893392d11 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -108,6 +108,7 @@ zr_infect_spawn_time_min 15 // Minimum time in which Mother Zombies should be zr_infect_spawn_time_max 15 // Maximum time in which Mother Zombies should be picked, after round start zr_infect_spawn_mz_ratio 7 // Ratio of all Players to Mother Zombies to be spawned at round start zr_infect_spawn_mz_min_count 1 // Minimum amount of Mother Zombies to be spawned at round start +zr_infect_min_count_req 2 // Minimum amount of Players required to spawn Mother Zombies at round start zr_respawn_delay 5.0 // Time before a zombie is automatically respawned, negative values (e.g. -1.0) disable this, note maps can still manually respawn at any time zr_default_winner_team 1 // Which team wins when time ran out [1 = Draw, 2 = Zombies, 3 = Humans] zr_mz_immunity_reduction 20 // How much mz immunity to reduce for each player per round (0-100) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index ea5481e4d..e269386bd 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -71,6 +71,7 @@ CConVar g_cvarInfectSpawnTimeMin("zr_infect_spawn_time_min", FCVAR_NONE, "M CConVar g_cvarInfectSpawnTimeMax("zr_infect_spawn_time_max", FCVAR_NONE, "Maximum time in which Mother Zombies should be picked, after round start", 15, true, 1, false, 0); CConVar g_cvarInfectSpawnMZRatio("zr_infect_spawn_mz_ratio", FCVAR_NONE, "Ratio of all Players to Mother Zombies to be spawned at round start", 7, true, 1, true, 64); CConVar g_cvarInfectSpawnMinCount("zr_infect_spawn_mz_min_count", FCVAR_NONE, "Minimum amount of Mother Zombies to be spawned at round start", 1, true, 0, false, 0); +CConVar g_cvarInfectSpawnMinCountReq("zr_infect_min_count_req", FCVAR_NONE, "Minimum amount of Players required to spawn Mother Zombies at round start", 2, true, 0, false, 0); CConVar g_cvarRespawnDelay("zr_respawn_delay", FCVAR_NONE, "Time before a zombie is automatically respawned, -1 disables this. Note that maps can still manually respawn at any time", 5.0f, true, -1.0f, false, 0.0f); CConVar g_cvarDefaultWinnerTeam("zr_default_winner_team", FCVAR_NONE, "Which team wins when time ran out [1 = Draw, 2 = Zombies, 3 = Humans]", CS_TEAM_SPECTATOR, true, 1, true, 3); CConVar g_cvarMZImmunityReduction("zr_mz_immunity_reduction", FCVAR_NONE, "How much mz immunity to reduce for each player per round (0-100)", 20, true, 0, true, 100); @@ -1284,17 +1285,14 @@ void ZR_InitialInfection() pCandidateControllers.AddToTail(pController); } - if (g_cvarInfectSpawnMZRatio.Get() <= 0) - { - Warning("Invalid Mother Zombie Ratio!!!"); - return; - } - // the num of mz to infect int iMZToInfect = pCandidateControllers.Count() / g_cvarInfectSpawnMZRatio.Get(); iMZToInfect = g_cvarInfectSpawnMinCount.Get() > iMZToInfect ? g_cvarInfectSpawnMinCount.Get() : iMZToInfect; bool vecIsMZ[MAXPLAYERS] = {false}; + if (pCandidateControllers.Count() < g_cvarInfectSpawnMinCountReq.Get()) + iMZToInfect = 0; + // get spawn points std::vector spawns = ZR_GetSpawns(); if (g_cvarInfectSpawnType.Get() == (int)EZRSpawnType::RESPAWN && !spawns.size()) From 80669ce63d9f1fd2a89ead6074d44042b872ee11 Mon Sep 17 00:00:00 2001 From: Vauff Date: Mon, 20 Apr 2026 19:05:38 -0400 Subject: [PATCH 05/32] Update MZ selection vector usage to std::vector --- src/zombiereborn.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index e269386bd..6e8d8bb9a 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -1271,7 +1271,7 @@ void ZR_InitialInfection() return; // mz infection candidates - CUtlVector pCandidateControllers; + std::vector vecCandidateControllers; for (int i = 0; i < GetGlobals()->maxClients; i++) { CCSPlayerController* pController = CCSPlayerController::FromSlot(i); @@ -1282,15 +1282,15 @@ void ZR_InitialInfection() if (!pPawn || !pPawn->IsAlive()) continue; - pCandidateControllers.AddToTail(pController); + vecCandidateControllers.push_back(pController); } // the num of mz to infect - int iMZToInfect = pCandidateControllers.Count() / g_cvarInfectSpawnMZRatio.Get(); + int iMZToInfect = vecCandidateControllers.size() / g_cvarInfectSpawnMZRatio.Get(); iMZToInfect = g_cvarInfectSpawnMinCount.Get() > iMZToInfect ? g_cvarInfectSpawnMinCount.Get() : iMZToInfect; bool vecIsMZ[MAXPLAYERS] = {false}; - if (pCandidateControllers.Count() < g_cvarInfectSpawnMinCountReq.Get()) + if (vecCandidateControllers.size() < g_cvarInfectSpawnMinCountReq.Get()) iMZToInfect = 0; // get spawn points @@ -1308,41 +1308,41 @@ void ZR_InitialInfection() // If we somehow don't have enough mother zombies after going through the players 5 times, if (iFailSafeCounter >= 5) { - FOR_EACH_VEC(pCandidateControllers, i) + for (int i = 0; i < vecCandidateControllers.size(); i++) { // at 5, reset everyone's immunity but mother zombies from this and last round // at 6, reset everyone's immunity but mother zombies from this round - ZEPlayer* pPlayer = pCandidateControllers[i]->GetZEPlayer(); + ZEPlayer* pPlayer = vecCandidateControllers[i]->GetZEPlayer(); if (pPlayer->GetImmunity() < 100 || (iFailSafeCounter >= 6 && !vecIsMZ[i])) pPlayer->SetImmunity(0); } } // a list of player who survived the previous mz roll of this round - CUtlVector pSurvivorControllers; - FOR_EACH_VEC(pCandidateControllers, i) + std::vector vecSurvivorControllers; + for (CCSPlayerController* pController : vecCandidateControllers) { // don't even bother with picked mz or player with 100 immunity - ZEPlayer* pPlayer = pCandidateControllers[i]->GetZEPlayer(); + ZEPlayer* pPlayer = pController->GetZEPlayer(); if (pPlayer && pPlayer->GetImmunity() < 100) - pSurvivorControllers.AddToTail(pCandidateControllers[i]); + vecSurvivorControllers.push_back(pController); } // no enough human even after triggering fail safe - if (iFailSafeCounter >= 6 && pSurvivorControllers.Count() == 0) + if (iFailSafeCounter >= 6 && vecSurvivorControllers.size() == 0) break; - while (pSurvivorControllers.Count() > 0 && iMZToInfect > 0) + while (vecSurvivorControllers.size() > 0 && iMZToInfect > 0) { - int randomindex = rand() % pSurvivorControllers.Count(); + int randomindex = rand() % vecSurvivorControllers.size(); - CCSPlayerController* pController = (CCSPlayerController*)pSurvivorControllers[randomindex]; + CCSPlayerController* pController = (CCSPlayerController*)vecSurvivorControllers[randomindex]; CCSPlayerPawn* pPawn = (CCSPlayerPawn*)pController->GetPawn(); - ZEPlayer* pPlayer = pSurvivorControllers[randomindex]->GetZEPlayer(); + ZEPlayer* pPlayer = vecSurvivorControllers[randomindex]->GetZEPlayer(); // roll for immunity if (rand() % 100 < pPlayer->GetImmunity()) { - pSurvivorControllers.FastRemove(randomindex); + vecSurvivorControllers.erase(vecSurvivorControllers.begin() + randomindex); continue; } From ad87c54900d26f01088bd619938861e9d0301436 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 3 Apr 2026 08:02:02 -0400 Subject: [PATCH 06/32] Update signatures for AnimGraph2 beta --- gamedata/cs2fixes.jsonc | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index b1fd950a6..0ffae643a 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -33,14 +33,14 @@ { "library": "server", "windows": "48 89 5C 24 ? 55 56 57 41 55 41 57 48 83 EC ? 44 8B 89", - "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 D5 41 54 49 89 F4 53 48 89 FB 48 83 EC ? 8B 87" + "linux": "55 48 89 E5 41 57 49 89 FF 41 56 41 55 41 54 49 89 D4 53 48 89 F3 48 81 EC" }, // Check vauff's pin in #scripting "ServerMovementUnlock": { "library": "server", - "windows": "0F 86 AF ? ? ? 0F 57 C0 0F 2E C2", - "linux": "0F 87 ? ? ? ? F3 0F 10 3D ? ? ? ? F3 0F 11 BD ? ? ? ? 48 89 DE" + "windows": "0F 86 A8 ? ? ? 0F 57 C0 0F 2E C2", + "linux": "0F 86 8A ? ? ? F3 0F 51 C9 49 8B 07" }, // String: "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam "CCSPlayerController_SwitchTeam": @@ -53,8 +53,8 @@ "CheckJumpButtonWater": { "library": "server", - "windows": "C8 42 EB ? 4C 8B 77 ? 4D 39 6E", - "linux": "C8 42 41 C7 84 24 ? ? ? ? ? ? ? ? 41 C7 84 24 ? ? ? ? ? ? ? ? E9" + "windows": "C8 42 EB ? 4C 8B 77 ? 4D 39 66", + "linux": "C8 42 41 C7 85 ? ? ? ? ? ? ? ? 41 C7 85 ? ? ? ? ? ? ? ? E9" }, // Called right after "Removed %s(%s)\n" "UTIL_Remove": @@ -112,15 +112,15 @@ "CBaseEntity_TakeDamageOld": { "library": "server", - "windows": "40 55 41 54 41 55 41 56 41 57 48 81 EC ? ? ? ? 48 8D 6C 24 ? 48 89 9D ? ? ? ? 45 33 ED", - "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 41 54 49 89 F4 53 48 89 D3 48 83 EC ? 48 85 D2" + "windows": "40 55 53 56 57 41 54 48 8D 6C 24 ? 48 81 EC ? ? ? ? 4D 8B E0", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 31 FF" }, // Should be xref'd right above "flGravity", takes a float arg "CBaseEntity::SetGravityScale": { "library": "server", "windows": "48 89 5C 24 ? 57 48 83 EC ? F3 0F 10 81 ? ? ? ? 48 8B F9 0F 29 74 24 ? 0F 28 F1 0F 2E C6 7A ? 74", - "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 81 EC ? ? ? ? 0F 2E 87 ? ? ? ? 7A ? 75 ? 48 81 C4 ? ? ? ? 5B 41 5C 41 5D 41 5E 41 5F 5D C3 0F 1F 40 ? 31 C9 31 F6 31 FF F3 0F 11 85 ? ? ? ? 66 89 8D ? ? ? ? BA ? ? ? ? B9 ? ? ? ? 66 0F EF C9 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 0F 29 8D ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? C7 85 ? ? ? ? ? ? ? ? E8 ? ? ? ? F3 0F 10 85 ? ? ? ? 85 C0 41 89 C4 0F 8E ? ? ? ? 48 63 8D ? ? ? ? 48 63 D0 31 F6 F3 0F 11 85 ? ? ? ? 48 C1 E2 ? 48 8B BD ? ? ? ? 48 C1 E1 ? 81 BD ? ? ? ? ? ? ? ? 40 0F 96 C6 E8 ? ? ? ? 8B 95 ? ? ? ? F3 0F 10 85 ? ? ? ? 48 89 85 ? ? ? ? 81 FA ? ? ? ? 0F 87" + "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 81 EC ? ? ? ? 0F 2E 87 ? ? ? ? 7A ? 75 ? 48 81 C4 ? ? ? ? 5B 41 5C 41 5D 41 5E 41 5F 5D C3 0F 1F 40 ? 31 C9 BE ? ? ? ? 66 0F EF C9 F3 0F 11 85 ? ? ? ? 48 8D BD ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 0F 29 8D ? ? ? ? 4C 8D A5 ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? 48 C7 85 ? ? ? ? ? ? ? ? C7 85 ? ? ? ? ? ? ? ? 66 89 8D ? ? ? ? E8 ? ? ? ? 48 8B 85 ? ? ? ? 48 8D 15 ? ? ? ? 83 85 ? ? ? ? ? F3 0F 10 85 ? ? ? ? C7 00 ? ? ? ? 48 8B 03 48 8B 80 ? ? ? ? 48 39 D0 0F 85 ? ? ? ? 8B 95 ? ? ? ? 4C 8D 7B ? 85 D2 0F 85 ? ? ? ? 80 BB ? ? ? ? ? 75" }, // "Game System %s is defined twice!\n" // Note that this signature points to the instruction with sm_pFirst which is the first qword referenced in the function. @@ -153,20 +153,20 @@ "windows": "44 88 4C 24 ? 53 57 41 54 41 56 41 57 48 83 EC", "linux": "55 48 8D 87 ? ? ? ? 48 89 E5 41 57 41 89 CF" }, - // String: "CNavMesh::GetNearestNavArea" + // String: "GetNearestNav" "CNavMesh_GetNearestNavArea": { "library": "server", - "windows": "48 89 5C 24 ? 44 89 4C 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24", - "linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 41 56 49 89 FE 41 55 48 8D 3D" + "windows": "48 89 5C 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 4C 8B 2D", + "linux": "55 48 89 E5 41 57 49 89 D7 41 56 41 55 49 89 FD 41 54 4D 89 C4" }, // Search "Changes's player's model", look for a function containing 'models/%s.vmdl'. Below V_snprintf is the one // This matches 2 functions, however they're literally identical "CBaseModelEntity_SetModel": { "library": "server", - "windows": "40 53 48 83 EC ? 48 8B D9 4C 8B C2 48 8B 0D ? ? ? ? 48 8D 54 24 ? 48 8B 01 FF 50 ? 48 8B 44 24", - "linux": "55 48 89 F2 48 89 E5 53 48 89 FB 48 8D 7D ? 48 83 EC ? 48 8D 05 ? ? ? ? 48 8B 30 48 8B 06" + "windows": "40 53 48 83 EC ? 48 8B D9 4C 8B C2 48 8B 0D ? ? ? ? 48 8D 54 24 ? 48 8B 01 FF 50 ? 48 8B 54 24", + "linux": "55 48 89 E5 53 48 89 FB 48 83 EC ? 48 8D 05 ? ? ? ? 48 8B 38 48 8B 07 FF 50 ? 48 89 DF" }, "CGameRules_TerminateRound": { @@ -177,7 +177,7 @@ "CCSPlayer_WeaponServices_CanUse": { "library": "server", - "windows": "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 83 EC ? 48 8B 01 48 8B FA", + "windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 54 41 55 41 56 41 57 48 83 EC ? 48 8B 01 48 8B FA", "linux": "55 48 8D 15 ? ? ? ? 48 89 E5 41 55 41 54 49 89 FC 53 48 89 F3 48 83 EC ? 48 8B 07 48 8B 80" }, "CCSPlayer_WeaponServices_EquipWeapon": @@ -196,7 +196,7 @@ { "library": "server", "windows": "48 89 5C 24 10 57 48 83 EC 30 48 8B DA 48 8B F9 48 85 C9", - "linux": "48 85 FF 74 ? 55 48 89 E5 41 55 49 89 FD" + "linux": "48 85 FF 74 ? 55 48 89 E5 41 55 41 54 49 89 FC" }, // Look for "SetEntityName", that will be the vscript binding definition // Scroll a bit down and you'll find something like this (note the offset): *(_QWORD *)(v453 + 64) = sub_1807B0350; @@ -227,7 +227,7 @@ { "library": "server", "windows": "48 89 5C 24 08 48 89 74 24 10 48 89 7C 24 18 4C 89 74 24 20 55 48 8D 6C 24 D1", - "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 41 89 CC 53 48 89 D3" + "linux": "55 48 89 E5 41 57 41 56 41 55 41 89 CD 41 54 53 48 89 D3" }, // search for "land_%s", this is called after that string is referenced (the one with 4 parameters). // (function that calls it also contains "T_Default.SuitLand"). @@ -249,14 +249,14 @@ { "library": "server", "windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 41 0F B6 F0", - "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 41 89 D4 53 48 89 FB 48 81 EC ? ? ? ? 40 38 B7" + "linux": "55 48 89 E5 41 57 49 89 FF 41 56 41 55 41 54 53 89 D3 48 81 EC ? ? ? ? 40 38 B7" }, // Use CBaseEntity::Use offset // This signature points directly to the instruction to patch "CPhysBox_Use": { "library": "server", - "windows": "4C 8B 43 ? 48 8D 8F ? ? ? ? 48 8B 13 E8 ? ? ? ? 48 8B 5C 24 ? 48 83 C4 ? 5F C3 CC CC CC CC 48 89 5C 24", + "windows": "4C 8B 43 ? 48 8D 8F ? ? ? ? 48 8B 13 E8 ? ? ? ? 48 8B 5C 24 ? 48 83 C4 ? 5F C3 CC CC CC CC 40 53", "linux": "49 8B 54 24 ? 45 31 C9 45 31 C0 C7 45 ? ? ? ? ? 49 8B 34 24 48 8D 4D ? 66 0F EF C0 48 C7 45 ? ? ? ? ? 48 8D BB ? ? ? ? E8 ? ? ? ? F6 45 ? ? 74 ? 48 8B 05 ? ? ? ? 48 8B 75 ? 48 8B 38 48 8B 07 FF 50 ? 48 83 C4" }, "CTakeDamageInfo": @@ -322,7 +322,7 @@ "CBasePlayerPawn_GetEyePosition": { "library": "server", - "windows": "48 89 5C 24 ? 57 48 83 EC ? 48 8B F9 48 8B DA 48 8B 89 ? ? ? ? 48 85 C9 74 ? 48 8B 01", + "windows": "48 89 74 24 ? 57 48 83 EC ? 48 8B F1 48 8B FA 48 8B 89 ? ? ? ? 48 85 C9 74 ? 48 8B 01", "linux": "55 48 89 E5 53 48 89 FB 48 83 EC ? 48 8B BF ? ? ? ? 48 85 FF 0F 84" }, "CBasePlayerPawn_GetEyeAngles": @@ -343,7 +343,7 @@ { "library": "server", "windows": "41 54 48 81 EC ? ? ? ? BA ? ? ? ? 48 8D 0D ? ? ? ? E8 ? ? ? ? 48 85 C0", - "linux": "55 48 8D 3D ? ? ? ? BE ? ? ? ? 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC ? ? ? ? E8 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 8B 10" + "linux": "55 48 8D 3D ? ? ? ? BE ? ? ? ? 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC ? ? ? ? E8 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 8B 00" }, // Location to CUtlMap unk that is referenced on Windows by function with "Notification about user penalty: %u/%u (%u sec)\n" string // On Linux, a qword appears twice in GameSystem_Think_CheckSteamBan, and thrice in a sub-function of the function used for Windows (1 top, 2 bottom), the only other reference to this qword is some convar registration function with two unks above, sm_mapGcBanInformation is the unk further away @@ -526,8 +526,8 @@ { "ServerMovementUnlock": { - "windows": "E9 B0 00 00 00 90", - "linux": "90 90 90 90 90 90" + "windows": "E9 A9 00 00 00 90", + "linux": "E9 8B 00 00 00 90" }, "FixWaterFloorJump": { From 17cd5b5596f547b588eafdb2cb8b234c9192bec1 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 3 Apr 2026 08:10:42 -0400 Subject: [PATCH 07/32] Update CTakeDamageInfo & CTakeDamageResult --- src/cs2_sdk/entity/ctakedamageinfo.h | 30 ++++++++++++++++++---------- src/cs2fixes.cpp | 2 +- src/detours.cpp | 4 ++-- src/zombiereborn.cpp | 6 +++--- src/zombiereborn.h | 2 +- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/cs2_sdk/entity/ctakedamageinfo.h b/src/cs2_sdk/entity/ctakedamageinfo.h index e1b032dff..1062d270a 100644 --- a/src/cs2_sdk/entity/ctakedamageinfo.h +++ b/src/cs2_sdk/entity/ctakedamageinfo.h @@ -136,52 +136,60 @@ class CTakeDamageInfo public: void* m_hScriptInstance; // 0xe0 | 224 AttackerInfo_t m_AttackerInfo; // 0xe8 | 232 - CUtlVector m_nDestructibleHitGroupsToForceDestroy; // 0x100 | 256 - bool m_bInTakeDamageFlow; // 0x118 | 280 + CUtlLeanVector m_DestructibleHitGroupRequests; // 0x100 | 256 CUtlLeanVector + bool m_bInTakeDamageFlow; // 0x110 | 272 private: [[maybe_unused]] int32_t m_nUnknown4; // 0x11c | 284 }; -static_assert(sizeof(CTakeDamageInfo) == 288); +static_assert(sizeof(CTakeDamageInfo) == 280); struct CTakeDamageResult { +public: CTakeDamageInfo* m_pOriginatingInfo; + CUtlLeanVector m_DestructibleHitGroupRequests; // CUtlLeanVector int32_t m_nHealthLost; int32_t m_nHealthBefore; - int32_t m_nDamageDealt; + float m_flDamageDealt; float m_flPreModifiedDamage; int32_t m_nTotalledHealthLost; - int32_t m_nTotalledDamageDealt; + float m_flTotalledDamageDealt; float m_flTotalledPreModifiedDamage; + float m_flNewDamageAccumulatorValue; + TakeDamageFlags_t m_nDamageFlags; bool m_bWasDamageSuppressed; bool m_bSuppressFlinch; HitGroup_t m_nOverrideFlinchHitGroup; +private: + [[maybe_unused]] uint8_t m_nUnknown0[0x8]; + +public: void CopyFrom(CTakeDamageInfo* pInfo) { m_pOriginatingInfo = pInfo; m_nHealthLost = static_cast(pInfo->m_flDamage); m_nHealthBefore = 0; - m_nDamageDealt = static_cast(pInfo->m_flDamage); + m_flDamageDealt = pInfo->m_flDamage; m_flPreModifiedDamage = pInfo->m_flDamage; m_nTotalledHealthLost = static_cast(pInfo->m_flDamage); - m_nTotalledDamageDealt = static_cast(pInfo->m_flDamage); + m_flTotalledDamageDealt = pInfo->m_flDamage; m_bWasDamageSuppressed = false; } CTakeDamageResult() = delete; - constexpr CTakeDamageResult(float damage) : + CTakeDamageResult(float damage) : m_pOriginatingInfo(nullptr), m_nHealthLost(static_cast(damage)), m_nHealthBefore(0), - m_nDamageDealt(static_cast(damage)), + m_flDamageDealt(damage), m_flPreModifiedDamage(damage), m_nTotalledHealthLost(static_cast(damage)), - m_nTotalledDamageDealt(static_cast(damage)), + m_flTotalledDamageDealt(damage), m_bWasDamageSuppressed(false) { } }; -static_assert(sizeof(CTakeDamageResult) == 48); \ No newline at end of file +static_assert(sizeof(CTakeDamageResult) == 80); \ No newline at end of file diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 681770f12..e331815be 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -1047,7 +1047,7 @@ bool CS2Fixes::Hook_OnTakeDamage_Alive(CTakeDamageResult* pDamageResult) if (g_cvarEnableZR.Get() && ZR_Hook_OnTakeDamage_Alive(pDamageResult->m_pOriginatingInfo, pPawn)) { pDamageResult->m_bWasDamageSuppressed = true; - pDamageResult->m_nDamageDealt = 0; + pDamageResult->m_flDamageDealt = 0.0f; RETURN_META_VALUE(MRES_SUPERCEDE, false); } diff --git a/src/detours.cpp b/src/detours.cpp index 534afdc53..aa369a806 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -155,8 +155,8 @@ int64 FASTCALL Detour_CBaseEntity_TakeDamageOld(CBaseEntity* pThis, CTakeDamageI CBaseEntity_TakeDamageOld(pThis, pInfo, pResult); - if (pResult->m_nDamageDealt > 0 && !pResult->m_bWasDamageSuppressed && g_cvarEnableZR.Get() && pThis->IsPawn()) - ZR_OnPlayerTakeDamage(reinterpret_cast(pThis), pInfo, pResult->m_nDamageDealt); + if (pResult->m_flDamageDealt > 0.0f && !pResult->m_bWasDamageSuppressed && g_cvarEnableZR.Get() && pThis->IsPawn()) + ZR_OnPlayerTakeDamage(reinterpret_cast(pThis), pInfo, pResult->m_flDamageDealt); return 1; } diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 6e8d8bb9a..2667c585b 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -989,7 +989,7 @@ void ZR_OnPlayerSpawn(CCSPlayerController* pController) }); } -void ZR_ApplyKnockback(CCSPlayerPawn* pHuman, CCSPlayerPawn* pVictim, int iDamage, const char* szWeapon, int hitgroup, float classknockback) +void ZR_ApplyKnockback(CCSPlayerPawn* pHuman, CCSPlayerPawn* pVictim, float flDamage, const char* szWeapon, int hitgroup, float classknockback) { std::shared_ptr pWeapon = g_pZRWeaponConfig->FindWeapon(szWeapon); std::shared_ptr pHitgroup = g_pZRHitgroupConfig->FindHitgroupIndex(hitgroup); @@ -1004,7 +1004,7 @@ void ZR_ApplyKnockback(CCSPlayerPawn* pHuman, CCSPlayerPawn* pVictim, int iDamag Vector vecKnockback; AngleVectors(pHuman->m_angEyeAngles(), &vecKnockback); - vecKnockback *= (iDamage * g_cvarKnockbackScale.Get() * flWeaponKnockbackScale * flHitgroupKnockbackScale * classknockback); + vecKnockback *= (flDamage * g_cvarKnockbackScale.Get() * flWeaponKnockbackScale * flHitgroupKnockbackScale * classknockback); pVictim->m_vecAbsVelocity = pVictim->m_vecAbsVelocity() + vecKnockback; } @@ -1592,7 +1592,7 @@ void ZR_Hook_ClientCommand_JoinTeam(CPlayerSlot slot, const CCommand& args) SpawnPlayer(pController); } -void ZR_OnPlayerTakeDamage(CCSPlayerPawn* pVictimPawn, const CTakeDamageInfo* pInfo, const int32_t damage) +void ZR_OnPlayerTakeDamage(CCSPlayerPawn* pVictimPawn, const CTakeDamageInfo* pInfo, const float damage) { // bullet & knife only if ((!(pInfo->m_bitsDamageType & DMG_BULLET) && !(pInfo->m_bitsDamageType & DMG_SLASH)) || !pInfo->m_pTrace || !pInfo->m_pTrace->m_pHitbox) diff --git a/src/zombiereborn.h b/src/zombiereborn.h index e00e177cc..8a548dfc3 100644 --- a/src/zombiereborn.h +++ b/src/zombiereborn.h @@ -267,7 +267,7 @@ void ZR_OnLevelInit(); void ZR_OnRoundPrestart(IGameEvent* pEvent); void ZR_OnRoundStart(IGameEvent* pEvent); void ZR_OnPlayerSpawn(CCSPlayerController* pController); -void ZR_OnPlayerTakeDamage(CCSPlayerPawn* pVictimPawn, const CTakeDamageInfo* pInfo, const int32 damage); +void ZR_OnPlayerTakeDamage(CCSPlayerPawn* pVictimPawn, const CTakeDamageInfo* pInfo, const float damage); void ZR_OnPlayerDeath(IGameEvent* pEvent); void ZR_OnRoundFreezeEnd(IGameEvent* pEvent); void ZR_OnRoundTimeWarning(IGameEvent* pEvent); From 35ba3c779db61cceafb1c91fa37f11e985a8f7ed Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 3 Apr 2026 14:27:42 -0400 Subject: [PATCH 08/32] Update offsets for AG2 beta --- gamedata/cs2fixes.jsonc | 84 +++++++++++++++++------------------ src/cs2_sdk/entity/services.h | 1 + 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 0ffae643a..07ea86b04 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -379,91 +379,91 @@ { "CBaseEntity::Precache": { - "windows": 6, - "linux": 7 + "windows": 7, + "linux": 8 }, "CBaseEntity::SetOwner": { - "windows": 52, - "linux": 51 + "windows": 53, + "linux": 52 }, // String: "%s<%i><%s><%s>" ChangeTeam() CTMDBG..." "CCSPlayerController_ChangeTeam": { - "windows": 102, - "linux": 101 + "windows": 103, + "linux": 102 }, "GetHammerUniqueId": { - "windows": 111, - "linux": 110 + "windows": 112, + "linux": 111 }, "CBaseEntity::Use": { - "windows": 144, - "linux": 143 + "windows": 145, + "linux": 144 }, "CBaseEntity::StartTouch": - { - "windows": 147, - "linux": 146 - }, - "CBaseEntity::Touch": { "windows": 148, "linux": 147 }, - "CBaseEntity::EndTouch": + "CBaseEntity::Touch": { "windows": 149, "linux": 148 }, + "CBaseEntity::EndTouch": + { + "windows": 150, + "linux": 149 + }, "Teleport": { - "windows": 162, - "linux": 161 + "windows": 163, + "linux": 162 }, // For these two, look for the names, you'll find vscript bindings // Scroll down to where the var + 64 gets set to a function, that calls the offset we want "IsPlayerPawn": { - "windows": 168, - "linux": 167 + "windows": 169, + "linux": 168 }, "IsPlayerController": { - "windows": 169, - "linux": 168 + "windows": 170, + "linux": 169 }, "CollisionRulesChanged": { - "windows": 185, - "linux": 184 + "windows": 186, + "linux": 185 }, "CCSPlayerController_Respawn": { - "windows": 272, - "linux": 274 + "windows": 273, + "linux": 275 }, // CBaseTrigger "PassesTriggerFilters": { - "windows": 266, - "linux": 267 + "windows": 273, + "linux": 274 }, // Actually a bit of a wrapper function now? Eventually calls a long function with "player_hurt" in the middle and then inserts userid, health, priority, attacker strings "CCSPlayerPawn::OnTakeDamage_Alive": { - "windows": 249, - "linux": 250 + "windows": 256, + "linux": 257 }, // Look for the kill command, go through its callback and you should a find call like this, with v9 being a pawn pointer: // return (*(*v9 + 2976LL))(v9, v27, 0LL); // 2976 (372 * 8) is the offset "CBasePlayerPawn_CommitSuicide": { - "windows": 400, - "linux": 400 + "windows": 390, + "linux": 390 }, "GameEntitySystem": { @@ -473,13 +473,13 @@ // In the function with "[%03d] Found: %s, firing\n", you'll find a call into a pointer offset just a bit higher, that's the offset * 8 "CGameRules_FindPickerEntity": { - "windows": 25, - "linux": 26 + "windows": 26, + "linux": 27 }, "CCSGameRules_GoToIntermission": { - "windows": 128, - "linux": 129 + "windows": 129, + "linux": 130 }, "CheckTransmitPlayerSlot": { @@ -502,18 +502,18 @@ // There's no easy way to find this, but it's a function that checks entity flags (0x370) and ends by calling RemoveFlag with 0x800000 (FL_BASEVELOCITY) "CCSPlayer_MovementServices::CheckMovingGround": { - "windows": 40, - "linux": 41 + "windows": 41, + "linux": 42 }, "CCSPlayer_WeaponServices::DropWeapon": { - "windows": 24, - "linux": 25 + "windows": 25, + "linux": 26 }, "CCSPlayer_WeaponServices::SelectItem": { - "windows": 26, - "linux": 27 + "windows": 27, + "linux": 28 }, // server.dll -> xref 'sv_phys_stop_at_collision' first __fastcall "CVPhys2World::GetTouchingList": diff --git a/src/cs2_sdk/entity/services.h b/src/cs2_sdk/entity/services.h index ffc1bd59d..bd9d30240 100644 --- a/src/cs2_sdk/entity/services.h +++ b/src/cs2_sdk/entity/services.h @@ -85,6 +85,7 @@ class CPlayerPawnComponent virtual void unk_16() = 0; virtual void unk_17() = 0; virtual void unk_18() = 0; + virtual void unk_19() = 0; public: DECLARE_SCHEMA_CLASS(CPlayerPawnComponent); From e1bbd94708d5f013f02433751d805871bd624207 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 3 Apr 2026 16:40:14 -0400 Subject: [PATCH 09/32] Fix SetPawn signature --- gamedata/cs2fixes.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 07ea86b04..c5fe3f774 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -151,7 +151,7 @@ { "library": "server", "windows": "44 88 4C 24 ? 53 57 41 54 41 56 41 57 48 83 EC", - "linux": "55 48 8D 87 ? ? ? ? 48 89 E5 41 57 41 89 CF" + "linux": "55 48 8D 87 ? ? ? ? 48 89 E5 41 57 41 56 41 89 CE 41 55 45 89 CD" }, // String: "GetNearestNav" "CNavMesh_GetNearestNavArea": From d703f3a7eb3b51ce3f6308b9650530427479791f Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 3 Apr 2026 16:56:41 -0400 Subject: [PATCH 10/32] Update example player class config with AG2 models --- configs/zr/playerclass.jsonc.example | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/configs/zr/playerclass.jsonc.example b/configs/zr/playerclass.jsonc.example index 0509d8634..3e3caf912 100644 --- a/configs/zr/playerclass.jsonc.example +++ b/configs/zr/playerclass.jsonc.example @@ -11,7 +11,7 @@ "models": [ // base class model entries can omit color (defaults to "255 255 255") and skins (defaults to [0]) { - "modelname": "characters/models/ctm_fbi/ctm_fbi.vmdl", + "modelname": "agents/models/ctm_fbi/ctm_fbi.vmdl", "color": "255 255 255", "skins": [ // either int or array of ints work 0 @@ -29,7 +29,7 @@ "base": "HumanClass1", // optional. missing keys will be inherited from base class "models": [ // model entry keys will override base class model entry keys only if both have 1 model entry { - "modelname": "characters/models/ctm_sas/ctm_sas.vmdl" + "modelname": "agents/models/ctm_sas/ctm_sas.vmdl" } ], "admin_flag": "b" // Only enabled in !zclass for ADMFLAG_GENERIC @@ -41,14 +41,14 @@ "models": [ // if base or child class have more than 2 model entries, all keys have to be defined and will override base model entries // model entry applied to the player will be picked randomly { - "modelname": "characters/models/s2ze/isaac_clarke/isaac_clarke.vmdl", // A custom model which will be automatically precached, must be loaded onto server/client by some means (e.g. MultiAddonManager) + "modelname": "agents/models/s2ze/isaac_clarke/isaac_clarke.vmdl", // A custom model which will be automatically precached, must be loaded onto server/client by some means (e.g. MultiAddonManager) "color": "255 255 255", "skins": [ 0, 1, 4 // picking skins out of 5 [0-4] available in S2ZE Isaac Clarke model to be applied to the player randomly ] }, { - "modelname": "characters/models/s2ze/isaac_clarke/isaac_clarke.vmdl", + "modelname": "agents/models/s2ze/isaac_clarke/isaac_clarke.vmdl", "color": "50 50 255", "skins": 3 } @@ -62,8 +62,8 @@ "health": 10000, "models": [ { - "modelname": "characters/models/tm_jumpsuit/tm_jumpsuit_varianta.vmdl", - "color": "255 150 150", + "modelname": "agents/models/tm_phoenix/tm_phoenix.vmdl", + "color": "255 100 100", "skins": [ 0 ] @@ -84,7 +84,7 @@ "health": 40000, "models": [ { - "modelname": "characters/models/tm_phoenix_heavy/tm_phoenix_heavy.vmdl", + "modelname": "agents/models/tm_phoenix/tm_phoenix.vmdl", "color": "255 100 100", "skins": [ 0 From 96a576f0227848f7ebae1cf369da535918a7ab34 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 3 Apr 2026 17:08:22 -0400 Subject: [PATCH 11/32] Remove AG1 playermodel animation fix --- AMBuilder | 2 -- CS2Fixes.vcxproj | 2 -- CS2Fixes.vcxproj.filters | 6 ---- src/cs2_sdk/entity/cbasemodelentity.cpp | 29 --------------- src/cs2_sdk/entity/cbasemodelentity.h | 5 ++- src/cs2_sdk/entity/ccsplayerpawn.cpp | 47 ------------------------- src/cs2_sdk/entity/ccsplayerpawn.h | 2 -- 7 files changed, 4 insertions(+), 89 deletions(-) delete mode 100644 src/cs2_sdk/entity/cbasemodelentity.cpp delete mode 100644 src/cs2_sdk/entity/ccsplayerpawn.cpp diff --git a/AMBuilder b/AMBuilder index db744b6ab..bb02216f2 100644 --- a/AMBuilder +++ b/AMBuilder @@ -51,8 +51,6 @@ for sdk_target in MMSPlugin.sdk_targets: 'src/utils/hud_manager.cpp', 'src/utils/utils.cpp', 'src/cs2_sdk/entity/services.cpp', - 'src/cs2_sdk/entity/ccsplayerpawn.cpp', - 'src/cs2_sdk/entity/cbasemodelentity.cpp', 'src/cs2_sdk/schema.cpp', 'src/ctimer.cpp', 'src/panoramavote.cpp', diff --git a/CS2Fixes.vcxproj b/CS2Fixes.vcxproj index 6b3d18f7f..61b6b5a96 100644 --- a/CS2Fixes.vcxproj +++ b/CS2Fixes.vcxproj @@ -222,8 +222,6 @@ - - diff --git a/CS2Fixes.vcxproj.filters b/CS2Fixes.vcxproj.filters index 2c6b571fa..68bb9f351 100644 --- a/CS2Fixes.vcxproj.filters +++ b/CS2Fixes.vcxproj.filters @@ -191,12 +191,6 @@ Source Files\cs2_sdk\entity - - Source Files\cs2_sdk\entity - - - Source Files\cs2_sdk\entity - Source Files diff --git a/src/cs2_sdk/entity/cbasemodelentity.cpp b/src/cs2_sdk/entity/cbasemodelentity.cpp deleted file mode 100644 index 0109de85b..000000000 --- a/src/cs2_sdk/entity/cbasemodelentity.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/** - * ============================================================================= - * CS2Fixes - * Copyright (C) 2023-2026 Source2ZE - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -#include "cbasemodelentity.h" -#include "ccsplayerpawn.h" - -void CBaseModelEntity::SetModel(const char* szModel) -{ - addresses::CBaseModelEntity_SetModel(this, szModel); - - if (IsPawn()) - ((CCSPlayerPawn*)this)->FixPlayerModelAnimations(); -} \ No newline at end of file diff --git a/src/cs2_sdk/entity/cbasemodelentity.h b/src/cs2_sdk/entity/cbasemodelentity.h index 0fc039774..bd3abae65 100644 --- a/src/cs2_sdk/entity/cbasemodelentity.h +++ b/src/cs2_sdk/entity/cbasemodelentity.h @@ -34,7 +34,10 @@ class CBaseModelEntity : public CBaseEntity SCHEMA_FIELD(float, m_flDissolveStartTime) SCHEMA_FIELD(Vector, m_vecViewOffset) - void SetModel(const char* szModel); + void SetModel(const char* szModel) + { + addresses::CBaseModelEntity_SetModel(this, szModel); + } void SetCollisionGroup(StandardCollisionGroups_t nCollisionGroup) { diff --git a/src/cs2_sdk/entity/ccsplayerpawn.cpp b/src/cs2_sdk/entity/ccsplayerpawn.cpp deleted file mode 100644 index 7c79aa3c4..000000000 --- a/src/cs2_sdk/entity/ccsplayerpawn.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * ============================================================================= - * CS2Fixes - * Copyright (C) 2023-2026 Source2ZE - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -#include "ccsplayerpawn.h" -#include "../ctimer.h" - -// Silly workaround for an animation bug that's been happening since 2024-11-06 CS2 update -// Clients need to see the new playermodel with zero velocity for at least (two?) ticks to properly render animations -void CCSPlayerPawn::FixPlayerModelAnimations() -{ - if (m_nActualMoveType() < MOVETYPE_WALK) - return; - - CHandle hPawn = GetHandle(); - Vector originalVelocity = m_vecAbsVelocity; - - Teleport(nullptr, nullptr, &vec3_origin); - SetMoveType(MOVETYPE_OBSOLETE); - - CTimer::Create(0.02f, TIMERFLAG_MAP | TIMERFLAG_ROUND, [hPawn, originalVelocity]() { - CCSPlayerPawn* pPawn = hPawn.Get(); - - if (!pPawn || !pPawn->IsAlive()) - return -1.0f; - - pPawn->SetMoveType(MOVETYPE_WALK); - pPawn->Teleport(nullptr, nullptr, &originalVelocity); - - return -1.0f; - }); -} \ No newline at end of file diff --git a/src/cs2_sdk/entity/ccsplayerpawn.h b/src/cs2_sdk/entity/ccsplayerpawn.h index 5f19ee26c..f418c2309 100644 --- a/src/cs2_sdk/entity/ccsplayerpawn.h +++ b/src/cs2_sdk/entity/ccsplayerpawn.h @@ -67,6 +67,4 @@ class CCSPlayerPawn : public CCSPlayerPawnBase { return reinterpret_cast(m_pCameraServices()); } - - void FixPlayerModelAnimations(); }; \ No newline at end of file From 5585d1f9106db919008f8d626fbda9d1c14c3489 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 14 Apr 2026 01:21:39 -0400 Subject: [PATCH 12/32] Fix detection of networked schema fields --- src/cs2_sdk/schema.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/cs2_sdk/schema.cpp b/src/cs2_sdk/schema.cpp index 10ff388cf..cdbfdab5c 100644 --- a/src/cs2_sdk/schema.cpp +++ b/src/cs2_sdk/schema.cpp @@ -21,6 +21,7 @@ #include "../common.h" #include "entity/cbaseentity.h" +#include "entity2/entityclass.h" #include "plat.h" #include "schemasystem/schemasystem.h" @@ -31,14 +32,20 @@ using SchemaTableMap_t = std::map; static constexpr uint32_t g_ChainKey = hash_32_fnv1a_const("__m_pChainEntity"); -static bool IsFieldNetworked(SchemaClassFieldData_t& field) +static bool IsFieldNetworked(const char* cppName, SchemaClassFieldData_t& field) { - for (int i = 0; i < field.m_nStaticMetadataCount; i++) - { - static auto networkEnabled = hash_32_fnv1a_const("MNetworkEnable"); - if (networkEnabled == hash_32_fnv1a_const(field.m_pStaticMetadata[i].m_pszName)) - return true; - } + if (!GameEntitySystem()) + return false; + + // Just use a random class to get access to the full database, as some schema classes don't have entity representations + CNetworkSerializerCodeGenDatabase* pDatabase = GameEntitySystem()->FindClassByName("CBaseEntity")->m_NetworkSerializerInfo->m_pDatabase; + int index = pDatabase->m_ClassInfos.Find(cppName); + + if (index == pDatabase->m_ClassInfos.InvalidIndex()) + return false; + + if (pDatabase->m_ClassInfos[index]->FindField(field.m_pszName)) + return true; return false; } @@ -60,7 +67,7 @@ static void InitChainOffset(SchemaClassInfoData_t* pClassInfo, SchemaKeyValueMap std::pair keyValuePair; keyValuePair.first = g_ChainKey; keyValuePair.second.offset = field.m_nSingleInheritanceOffset; - keyValuePair.second.networked = IsFieldNetworked(field); + keyValuePair.second.networked = IsFieldNetworked(pClassInfo->m_pszName, field); keyValueMap.insert(keyValuePair); return; @@ -87,7 +94,7 @@ static void InitSchemaKeyValueMap(SchemaClassInfoData_t* pClassInfo, SchemaKeyVa std::pair keyValuePair; keyValuePair.first = hash_32_fnv1a_const(field.m_pszName); keyValuePair.second.offset = field.m_nSingleInheritanceOffset; - keyValuePair.second.networked = IsFieldNetworked(field); + keyValuePair.second.networked = IsFieldNetworked(pClassInfo->m_pszName, field); keyValueMap.insert(keyValuePair); } From 95cecf9c592efba3c01f3d9254e0b73eefb1d729 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 14 Apr 2026 15:00:40 -0400 Subject: [PATCH 13/32] Fix EntWatch config dump crashing server when used from console --- src/entwatch.cpp | 59 ++++++++++++++++++++++++------------------------ src/entwatch.h | 3 +-- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/entwatch.cpp b/src/entwatch.cpp index 89b7b3ea1..847aafb50 100644 --- a/src/entwatch.cpp +++ b/src/entwatch.cpp @@ -1139,12 +1139,11 @@ void CEWHandler::LoadConfig(const char* sFilePath) bConfigLoaded = true; } -void CEWHandler::PrintLoadedConfig(CPlayerSlot slot) +void CEWHandler::PrintLoadedConfig(CCSPlayerController* pController) { - CCSPlayerController* player = CCSPlayerController::FromSlot(slot); if (!bConfigLoaded) { - ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "No config loaded."); + ClientPrint(pController, HUD_PRINTTALK, EW_PREFIX "No config loaded."); return; } @@ -1154,55 +1153,55 @@ void CEWHandler::PrintLoadedConfig(CPlayerSlot slot) i++; if (!item) { - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX "Null item in the item map at pos %d", i); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX "Null item in the item map at pos %d", i); continue; } - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX "------------ Item %02d ------------", i); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Name: %s", item->szItemName.c_str()); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX "ShortName: %s", item->szShortName.c_str()); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Hammerid: %s", item->szHammerid.c_str()); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Message: %s", item->bShowPickup ? "True" : "False"); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " UI: %s", item->bShowHud ? "True" : "False"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX "------------ Item %02d ------------", i); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Name: %s", item->szItemName.c_str()); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX "ShortName: %s", item->szShortName.c_str()); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Hammerid: %s", item->szHammerid.c_str()); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Message: %s", item->bShowPickup ? "True" : "False"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " UI: %s", item->bShowHud ? "True" : "False"); if (item->transfer == EWCfg_Auto) - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Transfer: Auto"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Transfer: Auto"); else if (item->transfer == EWCfg_Yes) - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Transfer: True"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Transfer: True"); else - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Transfer: False"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Transfer: False"); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " "); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " "); if (item->vecHandlers.size() == 0) { - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " No handlers set."); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " No handlers set."); } else { for (int j = 0; j < (item->vecHandlers).size(); j++) { // " " - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " --------- Handler %d ---------", j); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Type: %s", item->vecHandlers[j]->type == EWHandlerType::Button ? "Button" : "GameUi"); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Mode: %d", (int)item->vecHandlers[j]->mode); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Hammerid: %s", item->vecHandlers[j]->szHammerid.c_str()); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Event: %s", item->vecHandlers[j]->szOutput.c_str()); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Cooldown: %.1f", item->vecHandlers[j]->flCooldown); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Max Uses: %d", item->vecHandlers[j]->iMaxUses); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Message: %s", item->vecHandlers[j]->bShowUse ? "True" : "False"); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " --------- --------- ---------"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " --------- Handler %d ---------", j); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Type: %s", item->vecHandlers[j]->type == EWHandlerType::Button ? "Button" : "GameUi"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Mode: %d", (int)item->vecHandlers[j]->mode); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Hammerid: %s", item->vecHandlers[j]->szHammerid.c_str()); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Event: %s", item->vecHandlers[j]->szOutput.c_str()); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Cooldown: %.1f", item->vecHandlers[j]->flCooldown); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Max Uses: %d", item->vecHandlers[j]->iMaxUses); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Message: %s", item->vecHandlers[j]->bShowUse ? "True" : "False"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " --------- --------- ---------"); } } - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " "); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " "); if (item->vecTriggers.size() == 0) - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " No triggers set."); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " No triggers set."); else for (int j = 0; j < item->vecTriggers.size(); j++) - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX " Trigger %d: %s", j, item->vecTriggers[j].c_str()); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX " Trigger %d: %s", j, item->vecTriggers[j].c_str()); - ClientPrint(player, HUD_PRINTCONSOLE, EW_PREFIX "------------ ------- ------------"); + ClientPrint(pController, HUD_PRINTCONSOLE, EW_PREFIX "------------ ------- ------------"); } - ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "See console for output."); + ClientPrint(pController, HUD_PRINTTALK, EW_PREFIX "See console for output."); } void CEWHandler::ClearItems() @@ -2654,7 +2653,7 @@ CON_COMMAND_CHAT(ew_dump, "- Prints the currently loaded config to console") return; } - g_pEWHandler->PrintLoadedConfig(player->GetPlayerSlot()); + g_pEWHandler->PrintLoadedConfig(player); } CON_COMMAND_CHAT(hud, "- Toggle EntWatch HUD") diff --git a/src/entwatch.h b/src/entwatch.h index e2d387b57..32ce33a30 100644 --- a/src/entwatch.h +++ b/src/entwatch.h @@ -240,8 +240,7 @@ class CEWHandler void LoadMapConfig(const char* sMapName); void LoadConfig(const char* sFilePath); - void PrintLoadedConfig(int iSlot) { PrintLoadedConfig(CPlayerSlot(iSlot)); }; - void PrintLoadedConfig(CPlayerSlot slot); + void PrintLoadedConfig(CCSPlayerController* pController); void ClearItems(); From 61937f78dd649ed391f6988b0c58ae4a75fd4bc6 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 14 Apr 2026 18:33:42 -0400 Subject: [PATCH 14/32] Fix HammerID patch --- gamedata/cs2fixes.jsonc | 18 +++++++++++++----- src/entitylistener.cpp | 12 ------------ src/patches.cpp | 1 + 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index c5fe3f774..a636d658c 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -373,6 +373,13 @@ "library": "server", "windows": "48 89 5C 24 ? 57 48 83 EC ? 48 8B 02 48 8B F9 48 8B CA 48 8B DA FF 90 ? ? ? ? 84 C0 74 ? F3 0F 10 8F", "linux": "48 8B 06 55 48 89 E5 41 54 49 89 FC 48 89 F7 53 48 89 F3 FF 90" + }, + // Function that only has "hammerUniqueId" string, signature points to the outer if statement that determines if hammerid gets written to schema + "SetSchemaHammerUniqueId": + { + "library": "server", + "windows": "75 ? 48 8B 03 48 8B CB FF 90 ? ? ? ? 84 C0 74 ? 48 8D 05", + "linux": "75 ? 48 8B 03 48 8D 15 ? ? ? ? 48 8B 80 ? ? ? ? 48 39 D0 75 ? 48 83 C4" } }, "Offsets": @@ -393,11 +400,6 @@ "windows": 103, "linux": 102 }, - "GetHammerUniqueId": - { - "windows": 112, - "linux": 111 - }, "CBaseEntity::Use": { "windows": 145, @@ -548,6 +550,12 @@ { "windows": "49 89 F8 90", "linux": "48 89 DA 90 90" + }, + // jnz -> jmp + "SetSchemaHammerUniqueId": + { + "windows": "EB", + "linux": "EB" } } } diff --git a/src/entitylistener.cpp b/src/entitylistener.cpp index 576b6e11c..61a672b7b 100644 --- a/src/entitylistener.cpp +++ b/src/entitylistener.cpp @@ -31,16 +31,6 @@ CEntityListener* g_pEntityListener = nullptr; CConVar g_cvarGrenadeNoBlock("cs2f_noblock_grenades", FCVAR_NONE, "Whether to use noblock on grenade projectiles", false); -void Patch_GetHammerUniqueId(CEntityInstance* pEntity) -{ - static int offset = g_GameConfig->GetOffset("GetHammerUniqueId"); - void** vtable = *(void***)pEntity; - - // xor al, al -> mov al, 1 - // so it always returns true and allows hammerid to be copied into the schema prop - Plat_WriteMemory(vtable[offset], (uint8_t*)"\xB0\x01", 2); -} - void CEntityListener::OnEntitySpawned(CEntityInstance* pEntity) { #ifdef _DEBUG @@ -59,8 +49,6 @@ void CEntityListener::OnEntitySpawned(CEntityInstance* pEntity) void CEntityListener::OnEntityCreated(CEntityInstance* pEntity) { - ExecuteOnce(Patch_GetHammerUniqueId(pEntity)); - if (!V_strcmp("cs_gamerules", pEntity->GetClassname())) g_pGameRules = ((CCSGameRulesProxy*)pEntity)->m_pGameRules; } diff --git a/src/patches.cpp b/src/patches.cpp index 7f582de32..4e02eeaba 100644 --- a/src/patches.cpp +++ b/src/patches.cpp @@ -34,6 +34,7 @@ CMemPatch g_CommonPatches[] = CMemPatch("BotNavIgnore", "BotNavIgnore"), CMemPatch("CheckJumpButtonWater", "FixWaterFloorJump"), CMemPatch("CPhysBox_Use", "CPhysBox_Use"), + CMemPatch("SetSchemaHammerUniqueId", "SetSchemaHammerUniqueId"), }; CConVar cs2f_movement_unlocker_enable("cs2f_movement_unlocker_enable", FCVAR_NONE, "Whether to enable movement unlocker", false, From 3cd97ef4c8bb91264340d5e66ea95d30a96fa6c6 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 14 Apr 2026 19:17:22 -0400 Subject: [PATCH 15/32] Fix map vote schema fields not being networked --- src/map_votes.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/map_votes.cpp b/src/map_votes.cpp index 440d08f6c..c781b65c4 100644 --- a/src/map_votes.cpp +++ b/src/map_votes.cpp @@ -277,7 +277,10 @@ void CMapVoteSystem::StartVote() for (int i = 0; i < 10; i++) { g_pGameRules->m_nEndMatchMapGroupVoteTypes[i] = -1; + g_pGameRules->m_nEndMatchMapGroupVoteTypes.NetworkStateChanged(); + g_pGameRules->m_nEndMatchMapGroupVoteOptions[i] = -1; + g_pGameRules->m_nEndMatchMapGroupVoteOptions.NetworkStateChanged(); } return; @@ -326,6 +329,9 @@ void CMapVoteSystem::StartVote() g_pGameRules->m_nEndMatchMapGroupVoteTypes[i] = -1; g_pGameRules->m_nEndMatchMapGroupVoteOptions[i] = -1; } + + g_pGameRules->m_nEndMatchMapGroupVoteTypes.NetworkStateChanged(); + g_pGameRules->m_nEndMatchMapGroupVoteOptions.NetworkStateChanged(); } for (int i = 0; i < m_iVoteSize; i++) From 6c215c5811abadd4d94aba8e4e08c21df0928080 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 14 Apr 2026 21:58:56 -0400 Subject: [PATCH 16/32] Update movement unlocker for 2026-04-14 beta update --- gamedata/cs2fixes.jsonc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index a636d658c..8888a57b2 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -39,8 +39,8 @@ "ServerMovementUnlock": { "library": "server", - "windows": "0F 86 A8 ? ? ? 0F 57 C0 0F 2E C2", - "linux": "0F 86 8A ? ? ? F3 0F 51 C9 49 8B 07" + "windows": "0F 86 B0 ? ? ? 0F 57 C0 0F 2E C2", + "linux": "0F 87 ? ? ? ? F3 0F 10 35 ? ? ? ? F3 0F 11 B5" }, // String: "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam "CCSPlayerController_SwitchTeam": @@ -528,8 +528,8 @@ { "ServerMovementUnlock": { - "windows": "E9 A9 00 00 00 90", - "linux": "E9 8B 00 00 00 90" + "windows": "E9 B1 00 00 00 90", + "linux": "90 90 90 90 90 90" }, "FixWaterFloorJump": { From 85201c66cd7aaba06aaf20cbac6f9eb0d95f0829 Mon Sep 17 00:00:00 2001 From: Vauff Date: Mon, 20 Apr 2026 22:17:37 -0400 Subject: [PATCH 17/32] Switch GetPlayerName to std::string to fix invalid buffer reuse --- src/adminsystem.cpp | 126 ++++++++++----------- src/adminsystem.h | 4 +- src/commands.cpp | 24 ++-- src/cs2_sdk/entity/cbaseplayercontroller.h | 19 ++-- src/cs2fixes.cpp | 2 +- src/detours.cpp | 6 +- src/entities.cpp | 16 +-- src/entwatch.cpp | 58 +++++----- src/leader.cpp | 58 +++++----- src/map_votes.cpp | 4 +- src/panoramavote.cpp | 4 +- src/playermanager.cpp | 4 +- src/topdefender.cpp | 12 +- src/votemanager.cpp | 20 ++-- src/zombiereborn.cpp | 12 +- 15 files changed, 183 insertions(+), 186 deletions(-) diff --git a/src/adminsystem.cpp b/src/adminsystem.cpp index efbe0d274..1cdc67267 100644 --- a/src/adminsystem.cpp +++ b/src/adminsystem.cpp @@ -47,65 +47,65 @@ CAdminSystem* g_pAdminSystem = nullptr; void ParseInfraction(const CCommand& args, CCSPlayerController* pAdmin, bool bAdding, CInfractionBase::EInfractionType infType); const char* GetActionPhrase(CInfractionBase::EInfractionType infType, GrammarTense iTense, bool bAdding); -void PrintSingleAdminAction(const char* pszAdminName, const char* pszTargetName, const char* pszAction, const char* pszAction2 = "", const char* prefix = CHAT_PREFIX) +void PrintSingleAdminAction(std::string strAdminName, std::string strTargetName, const char* pszAction, const char* pszAction2 = "", const char* prefix = CHAT_PREFIX) { - ClientPrintAll(HUD_PRINTTALK, "%s" ADMIN_PREFIX "%s %s%s.", prefix, pszAdminName, pszAction, pszTargetName, pszAction2); + ClientPrintAll(HUD_PRINTTALK, "%s" ADMIN_PREFIX "%s %s%s.", prefix, strAdminName.c_str(), pszAction, strTargetName.c_str(), pszAction2); } -void PrintMultiAdminAction(ETargetType nType, const char* pszAdminName, const char* pszAction, const char* pszAction2 = "", const char* prefix = CHAT_PREFIX) +void PrintMultiAdminAction(ETargetType nType, std::string strAdminName, const char* pszAction, const char* pszAction2 = "", const char* prefix = CHAT_PREFIX) { switch (nType) { case ETargetType::ALL: - PrintSingleAdminAction(pszAdminName, "everyone", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "everyone", pszAction, pszAction2, prefix); break; case ETargetType::SPECTATOR: - PrintSingleAdminAction(pszAdminName, "spectators", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "spectators", pszAction, pszAction2, prefix); break; case ETargetType::T: - PrintSingleAdminAction(pszAdminName, "terrorists", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "terrorists", pszAction, pszAction2, prefix); break; case ETargetType::CT: - PrintSingleAdminAction(pszAdminName, "counter-terrorists", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "counter-terrorists", pszAction, pszAction2, prefix); break; case ETargetType::DEAD: - PrintSingleAdminAction(pszAdminName, "dead players", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "dead players", pszAction, pszAction2, prefix); break; case ETargetType::ALIVE: - PrintSingleAdminAction(pszAdminName, "alive players", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "alive players", pszAction, pszAction2, prefix); break; case ETargetType::BOT: - PrintSingleAdminAction(pszAdminName, "bots", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "bots", pszAction, pszAction2, prefix); break; case ETargetType::HUMAN: - PrintSingleAdminAction(pszAdminName, "humans", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "humans", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_SELF: - ClientPrintAll(HUD_PRINTTALK, "%s" ADMIN_PREFIX "%s everyone except %s%s.", prefix, pszAdminName, pszAction, pszAdminName, pszAction2); + ClientPrintAll(HUD_PRINTTALK, "%s" ADMIN_PREFIX "%s everyone except %s%s.", prefix, strAdminName.c_str(), pszAction, strAdminName.c_str(), pszAction2); break; case ETargetType::ALL_BUT_RANDOM: - PrintSingleAdminAction(pszAdminName, "everyone except a random player", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "everyone except a random player", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_RANDOM_T: - PrintSingleAdminAction(pszAdminName, "everyone except a random terrorist", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "everyone except a random terrorist", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_RANDOM_CT: - PrintSingleAdminAction(pszAdminName, "everyone except a random counter-terrorist", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "everyone except a random counter-terrorist", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_RANDOM_SPEC: - PrintSingleAdminAction(pszAdminName, "everyone except a random spectator", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "everyone except a random spectator", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_AIM: - PrintSingleAdminAction(pszAdminName, "everyone except a targetted player", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "everyone except a targetted player", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_SPECTATOR: - PrintSingleAdminAction(pszAdminName, "non-spectators", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "non-spectators", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_T: - PrintSingleAdminAction(pszAdminName, "non-terrorists", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "non-terrorists", pszAction, pszAction2, prefix); break; case ETargetType::ALL_BUT_CT: - PrintSingleAdminAction(pszAdminName, "non-counter-terrorists", pszAction, pszAction2, prefix); + PrintSingleAdminAction(strAdminName, "non-counter-terrorists", pszAction, pszAction2, prefix); break; } } @@ -245,7 +245,7 @@ CON_COMMAND_CHAT_FLAGS(kick, " - Kick a player", ADMFLAG_KICK) if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; for (int i = 0; i < iNumClients; i++) { @@ -255,10 +255,10 @@ CON_COMMAND_CHAT_FLAGS(kick, " - Kick a player", ADMFLAG_KICK) g_pEngineServer2->DisconnectClient(pTargetPlayer->GetPlayerSlot(), NETWORK_DISCONNECT_KICKED, "Kicked by an admin"); if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "kicked"); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "kicked"); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, "kicked"); + PrintMultiAdminAction(nType, strCommandPlayerName, "kicked"); } CON_COMMAND_CHAT_FLAGS(slay, " - Slay a player", ADMFLAG_SLAY) @@ -276,7 +276,7 @@ CON_COMMAND_CHAT_FLAGS(slay, " - Slay a player", ADMFLAG_SLAY) if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; for (int i = 0; i < iNumClients; i++) { @@ -284,11 +284,11 @@ CON_COMMAND_CHAT_FLAGS(slay, " - Slay a player", ADMFLAG_SLAY) pTarget->GetPawn()->CommitSuicide(false, true); if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "slayed"); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "slayed"); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, "slayed"); + PrintMultiAdminAction(nType, strCommandPlayerName, "slayed"); } CON_COMMAND_CHAT_FLAGS(slap, " [damage] - Slap a player", ADMFLAG_SLAY) @@ -306,7 +306,7 @@ CON_COMMAND_CHAT_FLAGS(slap, " [damage] - Slap a player", ADMFLAG_SLAY) if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; for (int i = 0; i < iNumClients; i++) { @@ -338,11 +338,11 @@ CON_COMMAND_CHAT_FLAGS(slap, " [damage] - Slap a player", ADMFLAG_SLAY) } if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "slapped"); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "slapped"); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, "slapped"); + PrintMultiAdminAction(nType, strCommandPlayerName, "slapped"); } CON_COMMAND_CHAT_FLAGS(goto, " - Teleport to a player", ADMFLAG_SLAY) @@ -422,7 +422,7 @@ CON_COMMAND_CHAT_FLAGS(noclip, "[name] - Toggle noclip on a player", ADMFLAG_CHE CCSPlayerController* pTarget = CCSPlayerController::FromSlot(pSlots[0]); CBasePlayerPawn* pPawn = pTarget->m_hPawn(); - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; if (!pPawn) return; @@ -430,12 +430,12 @@ CON_COMMAND_CHAT_FLAGS(noclip, "[name] - Toggle noclip on a player", ADMFLAG_CHE if (pPawn->m_nActualMoveType() == MOVETYPE_NOCLIP) { pPawn->SetMoveType(MOVETYPE_WALK); - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "disabled noclip on"); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "disabled noclip on"); } else { pPawn->SetMoveType(MOVETYPE_NOCLIP); - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "enabled noclip on"); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "enabled noclip on"); } } @@ -668,12 +668,12 @@ CON_COMMAND_CHAT_FLAGS(extend, " - Extend current map (negative value r g_pVoteManager->ExtendMap(iExtendTime); - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; if (iExtendTime < 0) - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "shortened map time %i minutes.", pszCommandPlayerName, iExtendTime * -1); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "shortened map time %i minutes.", strCommandPlayerName.c_str(), iExtendTime * -1); else - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "extended map time %i minutes.", pszCommandPlayerName, iExtendTime); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "extended map time %i minutes.", strCommandPlayerName.c_str(), iExtendTime); } CON_COMMAND_CHAT_FLAGS(pm, " - Private message a player. This will also show to all online admins", ADMFLAG_GENERIC) @@ -711,12 +711,12 @@ CON_COMMAND_CHAT_FLAGS(pm, " - Private message a player. This wi std::string strMessage = GetReason(args, 1, false); - const char* pszName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; if (player == pTarget) { // Player is PMing themselves (bind to display message in chat probably), so no need to echo to all admins - ClientPrint(player, HUD_PRINTTALK, "\x0A[SELF]\x0C %s\1: \x0B%s", pszName, strMessage.c_str()); + ClientPrint(player, HUD_PRINTTALK, "\x0A[SELF]\x0C %s\1: \x0B%s", strPlayerName.c_str(), strMessage.c_str()); return; } @@ -728,12 +728,12 @@ CON_COMMAND_CHAT_FLAGS(pm, " - Private message a player. This wi continue; if (pPlayer->IsAdminFlagSet(ADMFLAG_GENERIC) && CCSPlayerController::FromSlot(i) != player) - ClientPrint(CCSPlayerController::FromSlot(i), HUD_PRINTTALK, "\x0A[PM to %s]\x0C %s\1: \x0B%s", pTarget->GetPlayerName(), pszName, strMessage.c_str()); + ClientPrint(CCSPlayerController::FromSlot(i), HUD_PRINTTALK, "\x0A[PM to %s]\x0C %s\1: \x0B%s", pTarget->GetPlayerName().c_str(), strPlayerName.c_str(), strMessage.c_str()); } - ClientPrint(player, HUD_PRINTTALK, "\x0A[PM to %s]\x0C %s\1: \x0B%s", pTarget->GetPlayerName(), pszName, strMessage.c_str()); - ClientPrint(pTarget, HUD_PRINTTALK, "\x0A[PM]\x0C %s\1: \x0B%s", pszName, strMessage.c_str()); - Message("[PM to %s] %s: %s\n", pTarget->GetPlayerName(), pszName, strMessage.c_str()); + ClientPrint(player, HUD_PRINTTALK, "\x0A[PM to %s]\x0C %s\1: \x0B%s", pTarget->GetPlayerName().c_str(), strPlayerName.c_str(), strMessage.c_str()); + ClientPrint(pTarget, HUD_PRINTTALK, "\x0A[PM]\x0C %s\1: \x0B%s", strPlayerName.c_str(), strMessage.c_str()); + Message("[PM to %s] %s: %s\n", pTarget->GetPlayerName().c_str(), strPlayerName.c_str(), strMessage.c_str()); } size_t CountCharacters(const std::string& str) @@ -949,7 +949,7 @@ CON_COMMAND_CHAT(status, " - Checks a player's active punishments. Non-adm if (pTarget == player) ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "You have no active punishments."); else - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s has no active punishments.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s has no active punishments.", pTarget->GetPlayerName().c_str()); return; } @@ -962,7 +962,7 @@ CON_COMMAND_CHAT(status, " - Checks a player's active punishments. Non-adm strPunishment = "\2gagged\1"; ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s %s.", - pTarget == player ? "You are" : (std::string(pTarget->GetPlayerName()) + " is").c_str(), strPunishment.c_str()); + pTarget == player ? "You are" : (pTarget->GetPlayerName() + " is").c_str(), strPunishment.c_str()); } CON_COMMAND_CHAT_FLAGS(listdc, "- List recently disconnected players and their Steam64 IDs", ADMFLAG_GENERIC) @@ -999,7 +999,7 @@ CON_COMMAND_CHAT_FLAGS(money, " - Set a player's amount of money" if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; char szAction[64]; V_snprintf(szAction, sizeof(szAction), "set $%i money on", iMoney); @@ -1014,11 +1014,11 @@ CON_COMMAND_CHAT_FLAGS(money, " - Set a player's amount of money" pTarget->m_pInGameMoneyServices->m_iAccount = iMoney; if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), szAction, ""); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), szAction, ""); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, szAction, ""); + PrintMultiAdminAction(nType, strCommandPlayerName, szAction, ""); } CON_COMMAND_CHAT_FLAGS(health, " - Set a player's health", ADMFLAG_CHEATS) @@ -1044,7 +1044,7 @@ CON_COMMAND_CHAT_FLAGS(health, " - Set a player's health", ADMFLA if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_SPECTATOR, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; char szAction[64]; V_snprintf(szAction, sizeof(szAction), "set %i health on", iHealth); @@ -1067,11 +1067,11 @@ CON_COMMAND_CHAT_FLAGS(health, " - Set a player's health", ADMFLA pPawn->m_iHealth = iHealth; if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), szAction, ""); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), szAction, ""); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, szAction, ""); + PrintMultiAdminAction(nType, strCommandPlayerName, szAction, ""); } CON_COMMAND_CHAT_FLAGS(setpos, " - Set your origin", ADMFLAG_CHEATS) @@ -1118,7 +1118,7 @@ CON_COMMAND_CHAT_FLAGS(strip, " - Strip all the weapons/items of a player" if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_SPECTATOR, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; for (int i = 0; i < iNumClients; i++) { @@ -1140,11 +1140,11 @@ CON_COMMAND_CHAT_FLAGS(strip, " - Strip all the weapons/items of a player" pItemServices->StripPlayerWeapons(true); if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "stripped", ""); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "stripped", ""); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, "stripped", ""); + PrintMultiAdminAction(nType, strCommandPlayerName, "stripped", ""); } CON_COMMAND_CHAT_FLAGS(give, " - Give a weapon/item to a player", ADMFLAG_CHEATS) @@ -1170,7 +1170,7 @@ CON_COMMAND_CHAT_FLAGS(give, " - Give a weapon/item to a player", if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_SPECTATOR, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; char szAction[64]; V_snprintf(szAction, sizeof(szAction), "given %s to", args[2]); @@ -1221,11 +1221,11 @@ CON_COMMAND_CHAT_FLAGS(give, " - Give a weapon/item to a player", } if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), szAction, ""); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), szAction, ""); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, szAction, ""); + PrintMultiAdminAction(nType, strCommandPlayerName, szAction, ""); } #ifdef _DEBUG @@ -1272,7 +1272,7 @@ CON_COMMAND_CHAT_FLAGS(setteam, " - Set a player's team", ADM if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; constexpr const char* teams[] = {"none", "spectators", "terrorists", "counter-terrorists"}; @@ -1289,11 +1289,11 @@ CON_COMMAND_CHAT_FLAGS(setteam, " - Set a player's team", ADM pTarget->SwitchTeam(iTeam); if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "moved", szAction); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "moved", szAction); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, "moved", szAction); + PrintMultiAdminAction(nType, strCommandPlayerName, "moved", szAction); } #endif @@ -1950,7 +1950,7 @@ void ParseInfraction(const CCommand& args, CCSPlayerController* pAdmin, bool bAd return; } - const char* pszCommandPlayerName = pAdmin ? pAdmin->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = pAdmin ? pAdmin->GetPlayerName() : CONSOLE_NAME; for (int i = 0; i < iNumClients; i++) { @@ -1991,20 +1991,20 @@ void ParseInfraction(const CCommand& args, CCSPlayerController* pAdmin, bool bAd if (iNumClients == 1 || (bAdding && iDuration == 0)) { if (!bAdding) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), GetActionPhrase(infType, GrammarTense::Past, bAdding)); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), GetActionPhrase(infType, GrammarTense::Past, bAdding)); else if (iDuration > 0) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), GetActionPhrase(infType, GrammarTense::Past, bAdding), (" for " + FormatTime(iDuration, false)).c_str()); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), GetActionPhrase(infType, GrammarTense::Past, bAdding), (" for " + FormatTime(iDuration, false)).c_str()); else { std::string strAction = "permanently "; strAction.append(GetActionPhrase(infType, GrammarTense::Past, bAdding)); - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), strAction.c_str()); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), strAction.c_str()); } } } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, GetActionPhrase(infType, GrammarTense::Past, bAdding), + PrintMultiAdminAction(nType, strCommandPlayerName, GetActionPhrase(infType, GrammarTense::Past, bAdding), bAdding ? (" for " + FormatTime(iDuration, false)).c_str() : ""); g_pAdminSystem->SaveInfractions(); diff --git a/src/adminsystem.h b/src/adminsystem.h index fd899dbf2..76fcd7403 100644 --- a/src/adminsystem.h +++ b/src/adminsystem.h @@ -55,8 +55,8 @@ #define ADMIN_PREFIX "Admin %s has " #define CONSOLE_NAME "\2CONSOLE\1" // color it to indicate that it isnt a regular player using the command -void PrintSingleAdminAction(const char* pszAdminName, const char* pszTargetName, const char* pszAction, const char* pszAction2, const char* prefix); -void PrintMultiAdminAction(ETargetType nType, const char* pszAdminName, const char* pszAction, const char* pszAction2, const char* prefix); +void PrintSingleAdminAction(std::string strAdminName, std::string strTargetName, const char* pszAction, const char* pszAction2, const char* prefix); +void PrintMultiAdminAction(ETargetType nType, std::string strAdminName, const char* pszAction, const char* pszAction2, const char* prefix); enum GrammarTense { diff --git a/src/commands.cpp b/src/commands.cpp index 8e942ad12..516429315 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -452,7 +452,7 @@ CON_COMMAND_CHAT(hide, " - Hide nearby players") // Something has to really go wrong for this to happen if (!pZEPlayer) { - Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName()); + Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName().c_str()); return; } @@ -657,7 +657,7 @@ CON_COMMAND_CHAT(spec, "[name] - Spectate another player or join spectators") pObserverServices->m_iObserverMode = OBS_MODE_IN_EYE; pObserverServices->m_iObserverLastMode = OBS_MODE_ROAMING; pObserverServices->m_hObserverTarget = pTargetPlayer->GetPawn(); - ClientPrint(pPlayer, HUD_PRINTTALK, CHAT_PREFIX "Spectating player %s.", pTargetPlayer->GetPlayerName()); + ClientPrint(pPlayer, HUD_PRINTTALK, CHAT_PREFIX "Spectating player %s.", pTargetPlayer->GetPlayerName().c_str()); return -1.0f; }); } @@ -697,7 +697,7 @@ CON_COMMAND_CHAT(info, " - Get a player's information") CCSPlayerController* pTarget = CCSPlayerController::FromSlot(pSlots[i]); ZEPlayer* zpTarget = pTarget->GetZEPlayer(); - ClientPrint(player, HUD_PRINTCONSOLE, "%s", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTCONSOLE, "%s", pTarget->GetPlayerName().c_str()); ClientPrint(player, HUD_PRINTCONSOLE, "\tUser ID: %i", g_pEngineServer2->GetPlayerUserId(pTarget->GetPlayerSlot()).Get()); if (zpTarget->IsAuthenticated()) @@ -731,16 +731,16 @@ CON_COMMAND_CHAT(showteam, " - Get a player's current team") switch (pTarget->m_iTeamNum()) { case CS_TEAM_SPECTATOR: - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is a\x08 spectator\x01.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is a\x08 spectator\x01.", pTarget->GetPlayerName().c_str()); break; case CS_TEAM_T: - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is a\x09 terrorist\x01.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is a\x09 terrorist\x01.", pTarget->GetPlayerName().c_str()); break; case CS_TEAM_CT: - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is a\x0B counter-terrorist\x01.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is a\x0B counter-terrorist\x01.", pTarget->GetPlayerName().c_str()); break; default: - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is not on a team.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is not on a team.", pTarget->GetPlayerName().c_str()); } } @@ -865,8 +865,8 @@ CON_COMMAND_CHAT(test_target, " [blocked flag] [...] - Test string targett for (int i = 0; i < iNumClients; i++) { CCSPlayerController* pTarget = CCSPlayerController::FromSlot(pSlots[i]); - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Targeting %s", pTarget->GetPlayerName()); - Message("Targeting %s\n", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Targeting %s", pTarget->GetPlayerName().c_str()); + Message("Targeting %s\n", pTarget->GetPlayerName().c_str()); } } @@ -990,7 +990,7 @@ CON_COMMAND_CHAT(setcollisiongroup, " - Set a player's collision group") pTarget->m_hPawn->m_pCollision->m_collisionAttribute().m_nCollisionGroup = group; pTarget->GetPawn()->CollisionRulesChanged(); - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Setting collision group on %s from %d to %d.", pTarget->GetPlayerName(), oldgroup, group); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Setting collision group on %s from %d to %d.", pTarget->GetPlayerName().c_str(), oldgroup, group); } } @@ -1012,7 +1012,7 @@ CON_COMMAND_CHAT(setsolidtype, " - Set a player's solid type") pTarget->m_hPawn->m_pCollision->m_nSolidType = (SolidType_t)type; pTarget->GetPawn()->CollisionRulesChanged(); - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Setting solid type on %s from %d to %d.", pTarget->GetPlayerName(), oldtype, type); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Setting solid type on %s from %d to %d.", pTarget->GetPlayerName().c_str(), oldtype, type); } } @@ -1035,7 +1035,7 @@ CON_COMMAND_CHAT(setinteraction, " - Set a player's interaction flags") pTarget->m_hPawn->m_pCollision->m_collisionAttribute().m_nInteractsExclude = newInteract; pTarget->GetPawn()->CollisionRulesChanged(); - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Setting interaction flags on %s from %llx to %llx.", pTarget->GetPlayerName(), oldInteractAs, newInteract); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Setting interaction flags on %s from %llx to %llx.", pTarget->GetPlayerName().c_str(), oldInteractAs, newInteract); } } diff --git a/src/cs2_sdk/entity/cbaseplayercontroller.h b/src/cs2_sdk/entity/cbaseplayercontroller.h index 621e016f9..f31248c26 100644 --- a/src/cs2_sdk/entity/cbaseplayercontroller.h +++ b/src/cs2_sdk/entity/cbaseplayercontroller.h @@ -51,18 +51,15 @@ class CBasePlayerController : public CBaseEntity // - An observer pawn if spectating // - A bot pawn if controlling one CBasePlayerPawn* GetPawn() { return m_hPawn.Get(); } - const char* GetPlayerName() - { - static char buf[128]; - const char* name = m_iszPlayerName(); - strncpy(buf, name, sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - - size_t len = strlen(buf); - if (len > 0 && buf[len - 1] == ' ') - buf[len - 1] = '\0'; + std::string GetPlayerName() + { + std::string strName = m_iszPlayerName(); + + // Ignore space that might be added by clan tag name swap trick + if (!strName.empty() && strName.back() == ' ') + strName.pop_back(); - return buf; + return strName; } int GetPlayerSlot() { return entindex() - 1; } bool IsConnected() { return m_iConnected() == PlayerConnectedState::PlayerConnected; } diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index e331815be..2cca4031d 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -568,7 +568,7 @@ void CS2Fixes::Hook_DispatchConCommand(ConCommandRef cmdHandle, const CCommandCo continue; if (i == iCommandPlayerSlot.Get() || pPlayer->IsAdminFlagSet(ADMFLAG_GENERIC)) - ClientPrint(CCSPlayerController::FromSlot(i), HUD_PRINTTALK, " \4(%sADMINS) %s:\6 %s", bIsAdmin ? "" : "TO ", pController->GetPlayerName(), pszMessage); + ClientPrint(CCSPlayerController::FromSlot(i), HUD_PRINTTALK, " \4(%sADMINS) %s:\6 %s", bIsAdmin ? "" : "TO ", pController->GetPlayerName().c_str(), pszMessage); } } diff --git a/src/detours.cpp b/src/detours.cpp index aa369a806..14ef1255b 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -1,4 +1,4 @@ -/** +/** * ============================================================================= * CS2Fixes * Copyright (C) 2023-2026 Source2ZE @@ -383,10 +383,10 @@ void FASTCALL Detour_UTIL_SayText2Filter( CCSPlayerController* target = CCSPlayerController::FromSlot(slot); if (target) - Message("Chat from %s to %s: %s\n", param1, target->GetPlayerName(), param2); + Message("Chat from %s to %s: %s\n", param1, target->GetPlayerName().c_str(), param2); #endif - UTIL_SayText2Filter(filter, pEntity, eMessageType, msg_name, pEntity->GetPlayerName(), param2, param3, param4); + UTIL_SayText2Filter(filter, pEntity, eMessageType, msg_name, pEntity->GetPlayerName().c_str(), param2, param3, param4); } bool FASTCALL Detour_CCSPlayer_WeaponServices_CanUse(CCSPlayer_WeaponServices* pWeaponServices, CBasePlayerWeapon* pPlayerWeapon) diff --git a/src/entities.cpp b/src/entities.cpp index af8e3b977..7a5b13214 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -1,4 +1,4 @@ -/** +/** * ============================================================================= * CS2Fixes * Copyright (C) 2023-2026 Source2ZE @@ -445,7 +445,7 @@ namespace CGameUIHandler s_repository[key] = CGameUIState(pPlayer, GetButtons(pMovement) & ~IN_USE); #ifdef ENTITY_HANDLER_ASSERTION - Message("Activate Entity %d<%u> -> %s\n", pEntity->entindex(), key, pPlayer->GetController()->GetPlayerName()); + Message("Activate Entity %d<%u> -> %s\n", pEntity->entindex(), key, pPlayer->GetController()->GetPlayerName().c_str()); #endif return true; @@ -473,7 +473,7 @@ namespace CGameUIHandler DelayInput(pEntity, pPlayer, "InValue", "PlayerOff"); #ifdef ENTITY_HANDLER_ASSERTION - Message("Deactivate Entity %d -> %s\n", pEntity->entindex(), pPlayer->GetController()->GetPlayerName()); + Message("Deactivate Entity %d -> %s\n", pEntity->entindex(), pPlayer->GetController()->GetPlayerName().c_str()); #endif } else @@ -582,7 +582,7 @@ namespace CPointViewControlHandler if (pController->IsBot() || pController->m_bIsHLTV()) { - Warning("PointViewControl %s try enable for bot or HLTV: %s\n", it->second.m_name.c_str(), pController->GetPlayerName()); + Warning("PointViewControl %s try enable for bot or HLTV: %s\n", it->second.m_name.c_str(), pController->GetPlayerName().c_str()); return false; } @@ -594,13 +594,13 @@ namespace CPointViewControlHandler { if (vk == static_cast(key)) { - Warning("PointViewControl %s was enabled twice in a row! player: %s\n", vc.m_name.c_str(), pController->GetPlayerName()); + Warning("PointViewControl %s was enabled twice in a row! player: %s\n", vc.m_name.c_str(), pController->GetPlayerName().c_str()); return false; } vc.m_players.Remove(index); UpdatePlayerState(pPawn, INVALID_HANDLE, false, RESET_FOV); - Warning("PointViewControl %s already enabled for %s\n", vc.m_name.c_str(), pController->GetPlayerName()); + Warning("PointViewControl %s already enabled for %s\n", vc.m_name.c_str(), pController->GetPlayerName().c_str()); break; } } @@ -624,7 +624,7 @@ namespace CPointViewControlHandler if (pController->IsBot() || pController->m_bIsHLTV()) { - Warning("PointViewControl %s try disable for bot or HLTV: %s\n", it->second.m_name.c_str(), pController->GetPlayerName()); + Warning("PointViewControl %s try disable for bot or HLTV: %s\n", it->second.m_name.c_str(), pController->GetPlayerName().c_str()); return false; } @@ -661,7 +661,7 @@ namespace CPointViewControlHandler if (vk == static_cast(key)) continue; UpdatePlayerState(pPawn, INVALID_HANDLE, false, RESET_FOV); - Warning("PointViewControl %s already enabled for %s\n", vc.m_name.c_str(), pController->GetPlayerName()); + Warning("PointViewControl %s already enabled for %s\n", vc.m_name.c_str(), pController->GetPlayerName().c_str()); } } diff --git a/src/entwatch.cpp b/src/entwatch.cpp index 847aafb50..0ae9d07ff 100644 --- a/src/entwatch.cpp +++ b/src/entwatch.cpp @@ -341,7 +341,7 @@ void EWItemHandler::Use(float flCounterVal) if (szName != "") extra = " (" + szName + ")"; - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s \x05used %s%s%s", pController->GetPlayerName(), pItem->sChatColor, pItem->szItemName.c_str(), extra.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s \x05used %s%s%s", pController->GetPlayerName().c_str(), pItem->sChatColor, pItem->szItemName.c_str(), extra.c_str()); flLastShownUse = GetGlobals()->curtime; } @@ -433,7 +433,7 @@ void EWItemHandler::UseCounter(float flCounterVal) if (szName != "") extra = " (" + szName + ")"; - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s \x05used %s%s%s", pController->GetPlayerName(), pItem->sChatColor, pItem->szItemName.c_str(), extra.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s \x05used %s%s%s", pController->GetPlayerName().c_str(), pItem->sChatColor, pItem->szItemName.c_str(), extra.c_str()); flLastShownUse = GetGlobals()->curtime; } @@ -775,9 +775,9 @@ void EWItemInstance::Pickup(int slot) iTeamNum = pController->m_iTeamNum(); if (pPlayer->IsFakeClient()) - Message(EW_PREFIX "%s [BOT] has picked up %s (weaponid:%d)\n", pController->GetPlayerName(), szItemName.c_str(), iWeaponEnt); + Message(EW_PREFIX "%s [BOT] has picked up %s (weaponid:%d)\n", pController->GetPlayerName().c_str(), szItemName.c_str(), iWeaponEnt); else - Message(EW_PREFIX "%s [%llu] has picked up %s (weaponid:%d)\n", pController->GetPlayerName(), pPlayer->GetUnauthenticatedSteamId64(), szItemName.c_str(), iWeaponEnt); + Message(EW_PREFIX "%s [%llu] has picked up %s (weaponid:%d)\n", pController->GetPlayerName().c_str(), pPlayer->GetUnauthenticatedSteamId64(), szItemName.c_str(), iWeaponEnt); // Set clantag if (g_cvarUseEntwatchClantag.Get() && bShowHud) @@ -812,7 +812,7 @@ void EWItemInstance::Pickup(int slot) EndGlow(); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s \x05has picked up %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s \x05has picked up %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); } void EWItemInstance::Drop(EWDropReason reason, CCSPlayerController* pController) @@ -859,9 +859,9 @@ void EWItemInstance::Drop(EWDropReason reason, CCSPlayerController* pController) char sPlayerInfo[64]; if (pPlayer->IsFakeClient()) - V_snprintf(sPlayerInfo, sizeof(sPlayerInfo), "%s [BOT]", pController->GetPlayerName()); + V_snprintf(sPlayerInfo, sizeof(sPlayerInfo), "%s [BOT]", pController->GetPlayerName().c_str()); else - V_snprintf(sPlayerInfo, sizeof(sPlayerInfo), "%s [%llu]", pController->GetPlayerName(), pPlayer->GetUnauthenticatedSteamId64()); + V_snprintf(sPlayerInfo, sizeof(sPlayerInfo), "%s [%llu]", pController->GetPlayerName().c_str(), pPlayer->GetUnauthenticatedSteamId64()); switch (reason) { @@ -869,20 +869,20 @@ void EWItemInstance::Drop(EWDropReason reason, CCSPlayerController* pController) Message(EW_PREFIX "%s has dropped %s (weaponid:%d)\n", sPlayerInfo, szItemName.c_str(), iWeaponEnt); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 has dropped %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 has dropped %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); break; case EWDropReason::Infected: if (bAllowDrop) { Message(EW_PREFIX "%s got infected and dropped %s (weaponid:%d)\n", sPlayerInfo, szItemName.c_str(), iWeaponEnt); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 got infected and dropped %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 got infected and dropped %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); } else { Message(EW_PREFIX "%s got infected with %s (weaponid:%d)\n", sPlayerInfo, szItemName.c_str(), iWeaponEnt); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 got infected with %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 got infected with %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); } break; case EWDropReason::Death: @@ -890,13 +890,13 @@ void EWItemInstance::Drop(EWDropReason reason, CCSPlayerController* pController) { Message(EW_PREFIX "%s has died and dropped %s (weaponid:%d)\n", sPlayerInfo, szItemName.c_str(), iWeaponEnt); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 died and dropped %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 died and dropped %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); } else { Message(EW_PREFIX "%s has died with %s (weaponid:%d)\n", sPlayerInfo, szItemName.c_str(), iWeaponEnt); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 died with %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 died with %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); } break; case EWDropReason::Disconnect: @@ -904,13 +904,13 @@ void EWItemInstance::Drop(EWDropReason reason, CCSPlayerController* pController) { Message(EW_PREFIX "%s has disconnected and dropped %s (weaponid:%d)\n", sPlayerInfo, szItemName.c_str(), iWeaponEnt); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 disconnected and dropped %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 disconnected and dropped %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); } else { Message(EW_PREFIX "%s has disconnected with %s (weaponid:%d)\n", sPlayerInfo, szItemName.c_str(), iWeaponEnt); if (bShowPickup) - ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 disconnected with %s%s", pController->GetPlayerName(), sChatColor, szItemName.c_str()); + ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "\x03%s\x05 disconnected with %s%s", pController->GetPlayerName().c_str(), sChatColor, szItemName.c_str()); } break; case EWDropReason::Deleted: @@ -1757,49 +1757,49 @@ void CEWHandler::Transfer(CCSPlayerController* pCaller, int iItemInstance, CHand Vector vecOrigin = pReceiverPawn->GetAbsOrigin(); pItemWeapon->Teleport(&vecOrigin, nullptr, nullptr); - const char* pszCommandPlayerName = pCaller ? pCaller->GetPlayerName() : "Console"; + std::string strCommandPlayerName = pCaller ? pCaller->GetPlayerName() : "Console"; ZEPlayer* pZEReceiver = g_playerManager->GetPlayer(pReceiver->GetPlayerSlot()); char sReceiverInfo[64]; if (pZEReceiver->IsFakeClient()) - V_snprintf(sReceiverInfo, sizeof(sReceiverInfo), "%s [BOT]", pReceiver->GetPlayerName()); + V_snprintf(sReceiverInfo, sizeof(sReceiverInfo), "%s [BOT]", pReceiver->GetPlayerName().c_str()); else - V_snprintf(sReceiverInfo, sizeof(sReceiverInfo), "%s [%llu]", pReceiver->GetPlayerName(), pZEReceiver->GetUnauthenticatedSteamId64()); + V_snprintf(sReceiverInfo, sizeof(sReceiverInfo), "%s [%llu]", pReceiver->GetPlayerName().c_str(), pZEReceiver->GetUnauthenticatedSteamId64()); if (pOwner) { ZEPlayer* pZEOwner = g_playerManager->GetPlayer(pOwner->GetPlayerSlot()); char sOwnerInfo[64]; if (pZEOwner->IsFakeClient()) - V_snprintf(sOwnerInfo, sizeof(sOwnerInfo), "%s [BOT]", pOwner->GetPlayerName()); + V_snprintf(sOwnerInfo, sizeof(sOwnerInfo), "%s [BOT]", pOwner->GetPlayerName().c_str()); else - V_snprintf(sOwnerInfo, sizeof(sOwnerInfo), "%s [%llu]", pOwner->GetPlayerName(), pZEOwner->GetUnauthenticatedSteamId64()); + V_snprintf(sOwnerInfo, sizeof(sOwnerInfo), "%s [%llu]", pOwner->GetPlayerName().c_str(), pZEOwner->GetUnauthenticatedSteamId64()); Message("[EntWatch] %s transferred %s from %s to %s\n", - pszCommandPlayerName, + strCommandPlayerName.c_str(), g_pEWHandler->vecItems[iItemInstance]->szItemName.c_str(), sOwnerInfo, sReceiverInfo); ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "Admin\x02 %s\x01 has transferred%s %s\x01 from\x02 %s\x01 to\x02 %s\x01.", - pszCommandPlayerName, + strCommandPlayerName.c_str(), g_pEWHandler->vecItems[iItemInstance]->sChatColor, g_pEWHandler->vecItems[iItemInstance]->szItemName.c_str(), - pOwner->GetPlayerName(), - pReceiver->GetPlayerName()); + pOwner->GetPlayerName().c_str(), + pReceiver->GetPlayerName().c_str()); } else { Message("[EntWatch] %s transferred %s to %s\n", - pszCommandPlayerName, + strCommandPlayerName.c_str(), g_pEWHandler->vecItems[iItemInstance]->szItemName.c_str(), sReceiverInfo); ClientPrintAll(HUD_PRINTTALK, EW_PREFIX "Admin\x02 %s\x01 has transferred%s %s\x01 to\x02 %s\x01.", - pszCommandPlayerName, + strCommandPlayerName.c_str(), g_pEWHandler->vecItems[iItemInstance]->sChatColor, g_pEWHandler->vecItems[iItemInstance]->szItemName.c_str(), - pReceiver->GetPlayerName()); + pReceiver->GetPlayerName().c_str()); } } @@ -2410,7 +2410,7 @@ CON_COMMAND_CHAT_FLAGS(etransfer, " - Transfer an En return; } - const char* pszCommandPlayerName = player ? player->GetPlayerName() : "Console"; + std::string strCommandPlayerName = player ? player->GetPlayerName() : "Console"; bool bHasOngoing = false; auto ongoingTransfer = g_pEWHandler->mapTransfers.find(player->GetPlayerSlot()); @@ -2608,7 +2608,7 @@ CON_COMMAND_CHAT_FLAGS(etransfer, " - Transfer an En if (itemCount == 0) { - ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "%s does not have an item that can be transferred.", pOwner->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "%s does not have an item that can be transferred.", pOwner->GetPlayerName().c_str()); return; } else if (itemCount == 1) @@ -2618,7 +2618,7 @@ CON_COMMAND_CHAT_FLAGS(etransfer, " - Transfer an En } // itemCount > 1 - ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Found %d items owned by\x04 \"%s\"", itemCount, pOwner->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Found %d items owned by\x04 \"%s\"", itemCount, pOwner->GetPlayerName().c_str()); ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Enter\x02 !etransfer \x01 to complete the transfer"); std::shared_ptr transferInfo = std::make_shared(pReceiver->GetHandle(), GetGlobals()->curtime); diff --git a/src/leader.cpp b/src/leader.cpp index 5244bd809..a079040f8 100644 --- a/src/leader.cpp +++ b/src/leader.cpp @@ -531,7 +531,7 @@ CON_COMMAND_CHAT_LEADER(glow, "[name] [color] - Toggle glow highlight on a playe { ZEPlayer* pPlayer = player ? player->GetZEPlayer() : nullptr; bool bIsAdmin = pPlayer ? pPlayer->IsAdminFlagSet(FLAG_LEADER) : true; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; int pSlots[MAXPLAYERS]; @@ -572,13 +572,13 @@ CON_COMMAND_CHAT_LEADER(glow, "[name] [color] - Toggle glow highlight on a playe else if (iNumClients == 1) ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s %s %s glow on %s.", bIsAdmin ? "Admin" : "Leader", - pszCommandPlayerName, + strCommandPlayerName.c_str(), bEnablingGlow ? "enabled" : "disabled", - pTarget->GetPlayerName()); + pTarget->GetPlayerName().c_str()); } if (iNumClients > 1) // Can only hit this if bIsAdmin due to target flags - PrintMultiAdminAction(nType, pszCommandPlayerName, "toggled glow on", "", CHAT_PREFIX); + PrintMultiAdminAction(nType, strCommandPlayerName, "toggled glow on", "", CHAT_PREFIX); } CON_COMMAND_CHAT(glows, "- List all active player glows") @@ -648,13 +648,13 @@ CON_COMMAND_CHAT(vl, " - Vote for a player to become a leader") if (pPlayerTarget->IsLeader()) { - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is already a leader.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is already a leader.", pTarget->GetPlayerName().c_str()); return; } if (pPlayerTarget->HasPlayerVotedLeader(pPlayer)) { - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "You have already voted for %s to become a leader.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "You have already voted for %s to become a leader.", pTarget->GetPlayerName().c_str()); return; } @@ -666,15 +666,15 @@ CON_COMMAND_CHAT(vl, " - Vote for a player to become a leader") if (iLeaderVoteCount + 1 >= iNeededLeaderVoteCount) { Leader_SetNewLeader(pPlayerTarget); - Message("%s was voted for Leader with %i vote(s).\n", pTarget->GetPlayerName(), iNeededLeaderVoteCount); - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s has been voted as a leader!", pTarget->GetPlayerName()); + Message("%s was voted for Leader with %i vote(s).\n", pTarget->GetPlayerName().c_str(), iNeededLeaderVoteCount); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s has been voted as a leader!", pTarget->GetPlayerName().c_str()); ClientPrint(pTarget, HUD_PRINTTALK, CHAT_PREFIX "You became a leader! Use !leaderhelp and !leadercolors commands to list available leader commands and colors."); return; } pPlayerTarget->AddLeaderVote(pPlayer); ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s wants %s to become a Leader (%i/%i votes).", - player->GetPlayerName(), pTarget->GetPlayerName(), iLeaderVoteCount + 1, iNeededLeaderVoteCount); + player->GetPlayerName().c_str(), pTarget->GetPlayerName().c_str(), iLeaderVoteCount + 1, iNeededLeaderVoteCount); } CON_COMMAND_CHAT_LEADER(defend, "[name|duration] [duration] - Place a defend marker on the target player") @@ -686,7 +686,7 @@ CON_COMMAND_CHAT_LEADER(defend, "[name|duration] [duration] - Place a defend mar iDuration = V_StringToInt32(args[1], -1); else if (args.ArgC() > 2) iDuration = V_StringToInt32(args[2], -1); - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; int pSlots[MAXPLAYERS]; @@ -708,8 +708,8 @@ CON_COMMAND_CHAT_LEADER(defend, "[name|duration] [duration] - Place a defend mar ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Placed a defend marker on your position lasting %i seconds.", iDuration); else ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s %s placed a defend marker on %s's position lasting %i seconds.", - bIsAdmin ? "Admin" : "Leader", pszCommandPlayerName, - pTarget->GetPlayerName(), iDuration); + bIsAdmin ? "Admin" : "Leader", strCommandPlayerName.c_str(), + pTarget->GetPlayerName().c_str(), iDuration); } } @@ -717,7 +717,7 @@ CON_COMMAND_CHAT_LEADER(tracer, "[name] [color] - Toggle projectile tracers on a { ZEPlayer* pPlayer = player ? player->GetZEPlayer() : nullptr; bool bIsAdmin = pPlayer ? pPlayer->IsAdminFlagSet(FLAG_LEADER) : true; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; int pSlots[MAXPLAYERS]; @@ -735,10 +735,10 @@ CON_COMMAND_CHAT_LEADER(tracer, "[name] [color] - Toggle projectile tracers on a if (pPlayerTarget->GetTracerColor().a() == 255) { if (pTarget == player) - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Disabled tracers for yourself.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Disabled tracers for yourself."); else ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s %s disabled tracers for %s.", - bIsAdmin ? "Admin" : "Leader", pszCommandPlayerName, pTarget->GetPlayerName()); + bIsAdmin ? "Admin" : "Leader", strCommandPlayerName.c_str(), pTarget->GetPlayerName().c_str()); pPlayerTarget->SetTracerColor(Color(0, 0, 0, 0)); return; } @@ -753,10 +753,10 @@ CON_COMMAND_CHAT_LEADER(tracer, "[name] [color] - Toggle projectile tracers on a pPlayerTarget->SetTracerColor(color); if (pTarget == player) - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Enabled tracers for yourself.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Enabled tracers for yourself."); else ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s %s enabled tracers for %s.", - bIsAdmin ? "Admin" : "Leader", pszCommandPlayerName, pTarget->GetPlayerName()); + bIsAdmin ? "Admin" : "Leader", strCommandPlayerName.c_str(), pTarget->GetPlayerName().c_str()); } CON_COMMAND_CHAT(tracers, "- List all active player tracers") @@ -773,7 +773,7 @@ CON_COMMAND_CHAT_LEADER(beacon, "[name] [color] - Toggle beacon on a player") { ZEPlayer* pPlayer = player ? player->GetZEPlayer() : nullptr; bool bIsAdmin = pPlayer ? pPlayer->IsAdminFlagSet(FLAG_LEADER) : true; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; int pSlots[MAXPLAYERS]; @@ -814,13 +814,13 @@ CON_COMMAND_CHAT_LEADER(beacon, "[name] [color] - Toggle beacon on a player") else if (iNumClients == 1) ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s %s %s beacon on %s.", bIsAdmin ? "Admin" : "Leader", - pszCommandPlayerName, + strCommandPlayerName.c_str(), bEnablingBeacon ? "enabled" : "disabled", - pTarget->GetPlayerName()); + pTarget->GetPlayerName().c_str()); } if (iNumClients > 1) // Can only hit this if bIsAdmin due to target flags - PrintMultiAdminAction(nType, pszCommandPlayerName, "toggled beacon on", "", CHAT_PREFIX); + PrintMultiAdminAction(nType, strCommandPlayerName, "toggled beacon on", "", CHAT_PREFIX); } CON_COMMAND_CHAT(beacons, "- List all active player beacons") @@ -947,7 +947,7 @@ CON_COMMAND_CHAT_LEADER(leader, "[name] [color] - Force leader status on a playe return; } - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; int pSlots[MAXPLAYERS]; @@ -963,10 +963,10 @@ CON_COMMAND_CHAT_LEADER(leader, "[name] [color] - Force leader status on a playe ZEPlayer* pPlayerTarget = pTarget->GetZEPlayer(); if (!Leader_SetNewLeader(pPlayerTarget, args.ArgC() < 3 ? "" : args[2])) - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is already a leader.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is already a leader.", pTarget->GetPlayerName().c_str()); else ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s %s set %s as a leader.", - bIsAdmin ? "Admin" : "Leader", pszCommandPlayerName, pTarget->GetPlayerName()); + bIsAdmin ? "Admin" : "Leader", strCommandPlayerName.c_str(), pTarget->GetPlayerName().c_str()); } CON_COMMAND_CHAT_FLAGS(removeleader, "[name] - Remove leader status from a player", ADMFLAG_GENERIC) @@ -981,7 +981,7 @@ CON_COMMAND_CHAT_FLAGS(removeleader, "[name] - Remove leader status from a playe } ZEPlayer* pPlayer = player ? player->GetZEPlayer() : nullptr; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; int pSlots[MAXPLAYERS]; @@ -995,16 +995,16 @@ CON_COMMAND_CHAT_FLAGS(removeleader, "[name] - Remove leader status from a playe if (!pPlayerTarget->IsLeader()) { - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is not a leader. Use !leaders to list all current leaders.", pTarget->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s is not a leader. Use !leaders to list all current leaders.", pTarget->GetPlayerName().c_str()); return; } RemoveLeader(pTarget); if (player == pTarget) - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s resigned from being a leader.", player->GetPlayerName()); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s resigned from being a leader.", player->GetPlayerName().c_str()); else - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "removed leader from ", "", CHAT_PREFIX); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "removed leader from ", "", CHAT_PREFIX); } CON_COMMAND_CHAT(resign, "- Remove leader status from yourself") @@ -1030,5 +1030,5 @@ CON_COMMAND_CHAT(resign, "- Remove leader status from yourself") RemoveLeader(player); - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s resigned from being a leader.", player->GetPlayerName()); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s resigned from being a leader.", player->GetPlayerName().c_str()); } \ No newline at end of file diff --git a/src/map_votes.cpp b/src/map_votes.cpp index c781b65c4..5ce879c0c 100644 --- a/src/map_votes.cpp +++ b/src/map_votes.cpp @@ -452,7 +452,7 @@ bool CMapVoteSystem::RegisterPlayerVote(CPlayerSlot iPlayerSlot, int iVoteOption int iSlot = pController->GetPlayerSlot(); m_arrPlayerVotes[iSlot] = iVoteOption; - Message("Adding vote to map %i (%s) for player %s (slot %i).\n", iVoteOption, GetMapName(iMapIndexToVote), pController->GetPlayerName(), iSlot); + Message("Adding vote to map %i (%s) for player %s (slot %i).\n", iVoteOption, GetMapName(iMapIndexToVote), pController->GetPlayerName().c_str(), iSlot); // Update the winning map for every player vote UpdateWinningMap(); @@ -795,7 +795,7 @@ void CMapVoteSystem::AttemptNomination(CCSPlayerController* pController, const c g_pMapVoteSystem->SetPlayerNomination(iSlot, iMapIndex); int iNominations = g_pMapVoteSystem->GetTotalNominations(iMapIndex); - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "\x06%s \x01was nominated by %s. It now has %d nomination%s.", pMap->GetName(), pController->GetPlayerName(), iNominations, iNominations > 1 ? "s" : ""); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "\x06%s \x01was nominated by %s. It now has %d nomination%s.", pMap->GetName(), pController->GetPlayerName().c_str(), iNominations, iNominations > 1 ? "s" : ""); pPlayer->SetNominateTime(GetGlobals()->curtime); }); } diff --git a/src/panoramavote.cpp b/src/panoramavote.cpp index a691bce0e..bd7117fdd 100644 --- a/src/panoramavote.cpp +++ b/src/panoramavote.cpp @@ -381,8 +381,8 @@ CON_COMMAND_CHAT_FLAGS(cancelvote, "Cancels the ongoing vote.", ADMFLAG_CHANGEMA g_pPanoramaVoteHandler->EndVote(YesNoVoteEndReason::VoteEnd_Cancelled); - const char* pszCommandPlayerName = player ? player->GetPlayerName() : "Console"; - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "Admin %s has cancelled the vote.", pszCommandPlayerName); + std::string strCommandPlayerName = player ? player->GetPlayerName() : "Console"; + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "Admin %s has cancelled the vote.", strCommandPlayerName.c_str()); } CON_COMMAND_CHAT(revote, "Change your vote in the ongoing vote.") diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 3fd08da14..9f4ef075d 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -1053,7 +1053,7 @@ void CPlayerManager::UpdatePlayerStates() if (iCurrentPlayerState != iPreviousPlayerState) { #ifdef _DEBUG - Message("Player %s changed states from %s to %s\n", pController->GetPlayerName(), g_szPlayerStates[iPreviousPlayerState], g_szPlayerStates[iCurrentPlayerState]); + Message("Player %s changed states from %s to %s\n", pController->GetPlayerName().c_str(), g_szPlayerStates[iPreviousPlayerState], g_szPlayerStates[iCurrentPlayerState]); #endif pPlayer->SetPlayerState(iCurrentPlayerState); @@ -1590,7 +1590,7 @@ ETargetError CPlayerManager::GetPlayersFromString(CCSPlayerController* pPlayer, if (!pTarget || !pTarget->IsController() || !pTarget->IsConnected() || pTarget->m_bIsHLTV) continue; - if ((!bExactName && V_stristr(pTarget->GetPlayerName(), pszTarget)) || !V_strcmp(pTarget->GetPlayerName(), pszTarget)) + if ((!bExactName && V_stristr(pTarget->GetPlayerName().c_str(), pszTarget)) || !V_strcmp(pTarget->GetPlayerName().c_str(), pszTarget)) { nType = ETargetType::PLAYER; if (iNumClients == 1) diff --git a/src/topdefender.cpp b/src/topdefender.cpp index c962df750..ddc7d026e 100644 --- a/src/topdefender.cpp +++ b/src/topdefender.cpp @@ -241,9 +241,9 @@ void TD_OnRoundEnd(IGameEvent* pEvent) continue; if (i < 5) - ClientPrintAll(HUD_PRINTTALK, " %c%i. %s \x01- \x07%i DMG \x05(%i HITS | %.0f%% HS | %i KILL%s)", colorMap[MIN(i, 3)], i + 1, pController->GetPlayerName(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); + ClientPrintAll(HUD_PRINTTALK, " %c%i. %s \x01- \x07%i DMG \x05(%i HITS | %.0f%% HS | %i KILL%s)", colorMap[MIN(i, 3)], i + 1, pController->GetPlayerName().c_str(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); else - ClientPrint(pController, HUD_PRINTTALK, " \x0C%i. %s \x01- \x07%i DMG \x05(%i HITS | %.0f%% HS | %i KILL%s)", i + 1, pController->GetPlayerName(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); + ClientPrint(pController, HUD_PRINTTALK, " \x0C%i. %s \x01- \x07%i DMG \x05(%i HITS | %.0f%% HS | %i KILL%s)", i + 1, pController->GetPlayerName().c_str(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); if (i == 0) pPlayer->SetTopDefenderStatus(true); @@ -264,7 +264,7 @@ void TD_OnRoundEnd(IGameEvent* pEvent) if (!pController) continue; - ClientPrintAll(HUD_PRINTCONSOLE, "%i. %s - %i DMG (%i HITS | %.0f%% HS | %i KILL%s)", i + 1, pController->GetPlayerName(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); + ClientPrintAll(HUD_PRINTCONSOLE, "%i. %s - %i DMG (%i HITS | %.0f%% HS | %i KILL%s)", i + 1, pController->GetPlayerName().c_str(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); } ClientPrintAll(HUD_PRINTCONSOLE, "----------------------------------------------------------------------------------"); return -1.0f; @@ -338,11 +338,11 @@ void TopDefenderSearch(CCSPlayerController* player, const CCommand& args) if (!pTarget || sortedPlayers[i] != pTarget) continue; - ClientPrint(player, HUD_PRINTTALK, TD_PREFIX "RANK \4%d\1: \4%s \1 - \4%d \1DMG (\4%d \1HITS | \4%.0f%% \1HS | \4%d \1KILL%s)", i + 1, pController->GetPlayerName(), pTarget->GetTotalDamage(), pTarget->GetTotalHits(), ((double)pTarget->GetTotalHeadshots() / (double)pTarget->GetTotalHits()) * 100.0f, pTarget->GetTotalKills(), pTarget->GetTotalKills() == 1 ? "" : "S"); + ClientPrint(player, HUD_PRINTTALK, TD_PREFIX "RANK \4%d\1: \4%s \1 - \4%d \1DMG (\4%d \1HITS | \4%.0f%% \1HS | \4%d \1KILL%s)", i + 1, pController->GetPlayerName().c_str(), pTarget->GetTotalDamage(), pTarget->GetTotalHits(), ((double)pTarget->GetTotalHeadshots() / (double)pTarget->GetTotalHits()) * 100.0f, pTarget->GetTotalKills(), pTarget->GetTotalKills() == 1 ? "" : "S"); return; } - ClientPrint(player, HUD_PRINTTALK, TD_PREFIX "%s has no stats to display at this time.", CCSPlayerController::FromSlot(pSlots[0])->GetPlayerName()); + ClientPrint(player, HUD_PRINTTALK, TD_PREFIX "%s has no stats to display at this time.", CCSPlayerController::FromSlot(pSlots[0])->GetPlayerName().c_str()); } else { @@ -354,7 +354,7 @@ void TopDefenderSearch(CCSPlayerController* player, const CCommand& args) if (!pController) return; - ClientPrint(player, HUD_PRINTTALK, TD_PREFIX "RANK \4%d\1: \4%s \1- \4%d \1DMG (\4%d \1HITS | \4%.0f%% \1HS | \4%d \1KILL%s)", iRank, pController->GetPlayerName(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); + ClientPrint(player, HUD_PRINTTALK, TD_PREFIX "RANK \4%d\1: \4%s \1- \4%d \1DMG (\4%d \1HITS | \4%.0f%% \1HS | \4%d \1KILL%s)", iRank, pController->GetPlayerName().c_str(), pPlayer->GetTotalDamage(), pPlayer->GetTotalHits(), ((double)pPlayer->GetTotalHeadshots() / (double)pPlayer->GetTotalHits()) * 100.0f, pPlayer->GetTotalKills(), pPlayer->GetTotalKills() == 1 ? "" : "S"); } } } \ No newline at end of file diff --git a/src/votemanager.cpp b/src/votemanager.cpp index 9a136d542..ca730b42b 100644 --- a/src/votemanager.cpp +++ b/src/votemanager.cpp @@ -199,7 +199,7 @@ CON_COMMAND_CHAT(rtv, "- Vote to end the current map sooner") // Something has to really go wrong for this to happen if (!pPlayer) { - Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName()); + Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName().c_str()); return; } @@ -236,7 +236,7 @@ CON_COMMAND_CHAT(rtv, "- Vote to end the current map sooner") pPlayer->SetRTVVoteTime(GetGlobals()->curtime); if (!g_pVoteManager->CheckRTVStatus()) - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s wants to rock the vote (%i voted, %i needed).", player->GetPlayerName(), g_pVoteManager->GetCurrentRTVCount(), g_pVoteManager->GetNeededRTVCount()); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s wants to rock the vote (%i voted, %i needed).", player->GetPlayerName().c_str(), g_pVoteManager->GetCurrentRTVCount(), g_pVoteManager->GetNeededRTVCount()); } CON_COMMAND_CHAT(unrtv, "- Remove your vote to end the current map sooner") @@ -257,7 +257,7 @@ CON_COMMAND_CHAT(unrtv, "- Remove your vote to end the current map sooner") // Something has to really go wrong for this to happen if (!pPlayer) { - Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName()); + Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName().c_str()); return; } @@ -331,7 +331,7 @@ CON_COMMAND_CHAT(ve, "- Vote to extend current map") // Something has to really go wrong for this to happen if (!pPlayer) { - Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName()); + Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName().c_str()); return; } @@ -388,7 +388,7 @@ CON_COMMAND_CHAT(ve, "- Vote to extend current map") pPlayer->SetExtendVote(true); pPlayer->SetExtendVoteTime(GetGlobals()->curtime); - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s wants to extend the map (%i voted, %i needed).", player->GetPlayerName(), iCurrentExtendCount + 1, iNeededExtendCount); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "%s wants to extend the map (%i voted, %i needed).", player->GetPlayerName().c_str(), iCurrentExtendCount + 1, iNeededExtendCount); } CON_COMMAND_CHAT(unve, "- Remove your vote to extend current map") @@ -415,7 +415,7 @@ CON_COMMAND_CHAT(unve, "- Remove your vote to extend current map") // Something has to really go wrong for this to happen if (!pPlayer) { - Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName()); + Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName().c_str()); return; } @@ -467,11 +467,11 @@ CON_COMMAND_CHAT_FLAGS(disablertv, "- Disable the ability for players to vote to return; } - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; g_pVoteManager->SetRTVState(ERTVState::BLOCKED_BY_ADMIN); - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "disabled vote for RTV.", pszCommandPlayerName); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "disabled vote for RTV.", strCommandPlayerName.c_str()); } CON_COMMAND_CHAT_FLAGS(enablertv, "- Restore the ability for players to vote to end current map sooner", ADMFLAG_CHANGEMAP) @@ -488,11 +488,11 @@ CON_COMMAND_CHAT_FLAGS(enablertv, "- Restore the ability for players to vote to return; } - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; g_pVoteManager->SetRTVState(ERTVState::RTV_ALLOWED); - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "enabled vote for RTV.", pszCommandPlayerName); + ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "enabled vote for RTV.", strCommandPlayerName.c_str()); } CON_COMMAND_CHAT(extendsleft, "- Display amount of extends left for the current map") diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 2667c585b..00de82786 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -1995,7 +1995,7 @@ CON_COMMAND_CHAT_FLAGS(infect, "- Infect a player", ADMFLAG_GENERIC) if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TERRORIST | NO_DEAD, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; std::vector spawns = ZR_GetSpawns(); if (g_cvarInfectSpawnType.Get() == (int)EZRSpawnType::RESPAWN && !spawns.size()) @@ -2015,10 +2015,10 @@ CON_COMMAND_CHAT_FLAGS(infect, "- Infect a player", ADMFLAG_GENERIC) ZR_Infect(pTarget, pTarget, true); if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "infected", g_ZRRoundState == EZRRoundState::ROUND_START ? " as a mother zombie" : "", ZR_PREFIX); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "infected", g_ZRRoundState == EZRRoundState::ROUND_START ? " as a mother zombie" : "", ZR_PREFIX); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, "infected", g_ZRRoundState == EZRRoundState::ROUND_START ? " as mother zombies" : "", ZR_PREFIX); + PrintMultiAdminAction(nType, strCommandPlayerName, "infected", g_ZRRoundState == EZRRoundState::ROUND_START ? " as mother zombies" : "", ZR_PREFIX); // Note we skip MZ immunity when first infection is manually triggered if (g_ZRRoundState == EZRRoundState::ROUND_START) @@ -2055,7 +2055,7 @@ CON_COMMAND_CHAT_FLAGS(revive, "- Revive a player", ADMFLAG_GENERIC) if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_COUNTER_TERRORIST, nType)) return; - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; + std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; for (int i = 0; i < iNumClients; i++) { @@ -2069,8 +2069,8 @@ CON_COMMAND_CHAT_FLAGS(revive, "- Revive a player", ADMFLAG_GENERIC) ZR_StripAndGiveKnife(pPawn); if (iNumClients == 1) - PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "revived", "", ZR_PREFIX); + PrintSingleAdminAction(strCommandPlayerName, pTarget->GetPlayerName(), "revived", "", ZR_PREFIX); } if (iNumClients > 1) - PrintMultiAdminAction(nType, pszCommandPlayerName, "revived", "", ZR_PREFIX); + PrintMultiAdminAction(nType, strCommandPlayerName, "revived", "", ZR_PREFIX); } \ No newline at end of file From 788330c68f392787cc080fbcde0661a4c079124f Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 21 Apr 2026 14:05:45 -0400 Subject: [PATCH 18/32] Update SDK --- sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk b/sdk index e53b34f19..a66495095 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit e53b34f19bab25bea24306d2c9717dd1a107b64d +Subproject commit a664950956626e7690ee9c84f37a18ccbeb6fc7a From 72ec6b924c85185f56b7e9b5e641991eafd641d0 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 21 Apr 2026 21:50:32 -0400 Subject: [PATCH 19/32] Update signatures for 2026-04-21 CS2 update --- gamedata/cs2fixes.jsonc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 8888a57b2..26e8a32b4 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -256,7 +256,7 @@ "CPhysBox_Use": { "library": "server", - "windows": "4C 8B 43 ? 48 8D 8F ? ? ? ? 48 8B 13 E8 ? ? ? ? 48 8B 5C 24 ? 48 83 C4 ? 5F C3 CC CC CC CC 40 53", + "windows": "4C 8B 43 ? 48 8D 8F ? ? ? ? 48 8B 13 E8 ? ? ? ? 48 8B 5C 24 ? 48 83 C4 ? 5F C3 CC CC CC CC 48 89 5C 24", "linux": "49 8B 54 24 ? 45 31 C9 45 31 C0 C7 45 ? ? ? ? ? 49 8B 34 24 48 8D 4D ? 66 0F EF C0 48 C7 45 ? ? ? ? ? 48 8D BB ? ? ? ? E8 ? ? ? ? F6 45 ? ? 74 ? 48 8B 05 ? ? ? ? 48 8B 75 ? 48 8B 38 48 8B 07 FF 50 ? 48 83 C4" }, "CTakeDamageInfo": @@ -304,7 +304,7 @@ { "library": "server", "windows": "4C 89 44 24 ? F3 0F 11 4C 24 ? 55 53 56", - "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 41 54 48 8D 3D ? ? ? ? 53 48 81 EC" + "linux": "55 48 89 E5 41 57 49 89 FF 41 56 48 8D 3D ? ? ? ? 41 55 41 54 53 48 81 EC" }, "TraceFunc": { From b406c27cd721b0cbcf322e4b90bda84c79855fcd Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 23 Apr 2026 16:23:08 -0400 Subject: [PATCH 20/32] Remove cheat flag from mp_flinch_punch_scale --- src/cvars.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index a32592a4c..89863117f 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -24,7 +24,7 @@ static uint64 g_iFlagsToRemove = (FCVAR_HIDDEN | FCVAR_DEVELOPMENTONLY); -static constexpr const char* pUnCheatCvars[] = {"bot_stop", "bot_freeze", "bot_zombie"}; +static constexpr const char* pUnCheatCvars[] = {"bot_stop", "bot_freeze", "bot_zombie", "mp_flinch_punch_scale"}; static constexpr const char* pUnCheatCmds[] = {"report_entities", "endround"}; void UnlockConVars() From 612aa57d3ab88eee854c1c61fa09f763c5f67822 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Thu, 23 Apr 2026 18:14:24 -0400 Subject: [PATCH 21/32] Add particle flashlight & fix light_barn flashlight attachment (#439) * Update playermanager.cpp * particle file and cfg * adjustments * ops * rename this too ig --------- Co-authored-by: Vauff --- PackageScript | 1 + .../cs2fixes/simple_flashlight.vpcf_c | Bin 0 -> 3514 bytes .../particles/cs2fixes/simple_flashlight.vpcf | 855 ++++++++++++++++++ cfg/cs2fixes/cs2fixes.cfg | 5 +- src/playermanager.cpp | 15 +- 5 files changed, 871 insertions(+), 5 deletions(-) create mode 100644 assets/particles/cs2fixes/simple_flashlight.vpcf_c create mode 100644 assets_source/particles/cs2fixes/simple_flashlight.vpcf diff --git a/PackageScript b/PackageScript index 44cfacd19..ab59251e6 100644 --- a/PackageScript +++ b/PackageScript @@ -130,6 +130,7 @@ for task in MMSPlugin.binaries: builder.AddCopy(os.path.join('assets', 'particles', MMSPlugin.metadata['name'], 'leader_defend_mark_ground.vpcf_c'), particles_cs2f_folder) builder.AddCopy(os.path.join('assets', 'particles', MMSPlugin.metadata['name'], 'leader_tracer.vpcf_c'), particles_cs2f_folder) builder.AddCopy(os.path.join('assets', 'particles', MMSPlugin.metadata['name'], 'napalm_fire.vpcf_c'), particles_cs2f_folder) + builder.AddCopy(os.path.join('assets', 'particles', MMSPlugin.metadata['name'], 'simple_flashlight.vpcf_c'), particles_cs2f_folder) materials_cs2f_folder = builder.AddFolder(os.path.join(packages[sdk_name].sdk_name, 'materials', MMSPlugin.metadata['name'])) builder.AddCopy(os.path.join('assets', 'materials', MMSPlugin.metadata['name'], 'leader_defend_mark.vtex_c'), materials_cs2f_folder) diff --git a/assets/particles/cs2fixes/simple_flashlight.vpcf_c b/assets/particles/cs2fixes/simple_flashlight.vpcf_c new file mode 100644 index 0000000000000000000000000000000000000000..137c39bb770de6ebe9e16778110ddc04a04b96a1 GIT binary patch literal 3514 zcmaKuYj7LY703T~wOUJ&Ey9lm(Qs_*l?U#OmJ_v9=kX;`nU(Q)5S7Cm5=`3qxGk#|MTUW)b}*Ka5pXZhz2iD*-mYD zkBx*YlZ*TMg<8FoHX2PQDH_743ZtS48}*VZbna*~VqDXO!RrDIZaG>-7xqBK9-h+X zs9|gMhAv7|I=5@OHeGWz&onAiw74L+RjK8Ed+ttyhJafegK2AuO0=NkfJn!&C4G2JZF>gRCEm=;#U(hMhr zMv??->dq%P+z=Iw>&NjysNm4xGgVbQf_6o};DM^?pevl?*IogyaEJP8_ zHyKQfPTIoyE;_Ir!QJrQgWyW$yMeJYEGDWd3)}b5iEEl(RfTOft%}HK_OEbypWug8 zF(oWvbU=EIrFdBv4?$io-Cvrv%w|KYw&VUfpR1Tn!-?Qy=4f?Ma?Fyg3(-K@o&`#1 zHp|?$g)@szdj}Smn+;)c$Fz_rwI3U!dXw+upMsDzc8D2 zs;)WC3cQofri)}5nlrAO+-b)-BrL%lu}^bqnlWb1jp3QN-l*}UsPK6co@;?178F&~ zd824?!=5s&dd|{FOME{YE1Igg3=#Wk4CPJx2uozl%HbWr!|W-mK<}<{tC|_{C?5kU zX;?F~I2vT1n}|~ZdMJb}Bkvlq--iSvBM$@15cR}x%uBtGY@gM3pwL21-=J&lqsyqd zAB&x2R3LvO`G62X>(EX_h$zuPEGO^04bje(=<8YuIof>)(HaxCOR-UZw_j0OgKa^dAFD&55W*oDzw}Y@ zhr-^F-yde~A>a7N1zPi2apS|Y%KN**FaIHPe8slY|EzrfaaR>oMjs_-c2E5Xv6USD zY8=EV678Jp?c2D;qsnwO(J&}8gbE``g@^2dnaqLpu;5*aG?tjr#4PPwwI~8vJy=+w#T|!NYD=D+j~9#a#IDl5oSI4I)b!4D zmgc(7=*(y1c*_>L8-((fAX~Oi;UhVB$r0!jmp$PD9J}NJ)^R+a$PdwqvTLn97)s5H zlNcr|{Rn3R`M6q4Co-v0>OiVMld`5m0n!a+qo^)9i>M)zZe^8={?iMVg&bzFqS@(M zm-HvRJzgpv$frt~bTOsIGdHo0MlXgZ;`u)CWLixniY9w0qfr#&`d+R##aECdMO53+ zZM@^^>@S51*SSSHu(Wd1S%cDEQE|*D*bz52nTEI?gJo4bz_`d+RbkEIq)IMj)+aP0 zh!~&Sh~Zt_4&zusn>NOEtx<$0g6o8+1~D{YR)3ELS&e6txrx$5E}1GNa@j&Lo;`ze zlI>UpgE#D&=@gn}3NH)Tl1mQy(J@2}`w<>Fi087VW{agn@&;B<=~tkdYdVxxehyz0 z>-ZeG*#N_}7@iT8HJG28qK#C33s?udvuNfj4xbSu;3LJRRc=zwsr()PLN=E!q)Np} zb*z-lWmD_0VZIRq{>nr?rDoFEe%wdGF9l(8y8%{AkEc`WEx2Y%KLYt@XzRiH3GE$> zrR&pq(<2X}x7>{_8Es}K-b#>;Ek4e5z050zH{ulv-eVMCt9C*dXC!tflh3e1I-8#? zzRq|iK9Nr)cjM3mWr}hBEyhA%Bj_9qK>8z-9%WsFt%wdii0?R+8U=e!3FZ~n(t!

<90vB#?tWuIq?h9 za5ApG?s{bTVzvvjp+wUfWqG@yYX<4xc^ZR;V;_)CCe1q6jLRQAh;Vw^JH~bG&I$RP zcPXNOE{LC!;9;5k-c;fSxp$^l_JlB$F!dQWUmiDg-JBhw?jesHl@1$8p*uV)56vX< z+u&X2c_xv+d`sBm^>-qc)aEd`lrC6)DxBld2nu-5GWI0cX@(iu zlVt%%k(aanjJe%I7n)(!bXMW*|4u-6DQtPmrR1ahM3D@5HYynLek>&>RW+3@mXfJ) zGWW@BakH`~n=2-E&3huo1*qei(5qQ|D1Vma$o*CKl4Silis|G^dolR z47Fd*(^R0~CO%0<)ayfGh}x7m3tdzXv?An#w~uW=cNcwusMLWjkK@LezLp(e_cF#j zk|cQ;*3lCRLu)6FNRmvwjM8NtEhi9douhl~c|?^t9J_px>}Jux2K2X)oQuK#n`qZk zmThH=k!}*Ghgd=M5|OKTL7L_TQFiq45*HrEx4zIA*m3%GFY%@G!L=u7`e=6a8&5Fw|M=!G2Hv7aJ#-RRvKDMQ7T<>F z{Yt*9r+wOUZsHA1pfj`;kFIWy+z3wsp-=E`xNVEn?oFXD lk|KK>mac76lzS06BCTo%e**<{HRS*R literal 0 HcmV?d00001 diff --git a/assets_source/particles/cs2fixes/simple_flashlight.vpcf b/assets_source/particles/cs2fixes/simple_flashlight.vpcf new file mode 100644 index 000000000..0f90aa630 --- /dev/null +++ b/assets_source/particles/cs2fixes/simple_flashlight.vpcf @@ -0,0 +1,855 @@ + +{ + _class = "CParticleSystemDefinition" + m_nBehaviorVersion = 12 + m_flConstantRadius = 60.0 + m_nMaxParticles = 1 + m_controlPointConfigurations = + [ + { + m_name = "preview" + m_drivers = + [ + { + m_iAttachType = "PATTACH_WORLDORIGIN" + m_entityName = "self" + }, + ] + }, + ] + m_PreEmissionOperators = + [ + { + _class = "C_OP_SetControlPointToPlayer" + m_nCP1 = 0 + m_bOrientToEyes = true + m_nPosition = "PARTICLE_EYES" + m_Notes = "easter" + }, + ] + m_Emitters = + [ + { + _class = "C_OP_InstantaneousEmitter" + m_nParticlesToEmit = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 1.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_bReverseOrder = false + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_strSnapshotSubset = "" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + }, + ] + m_Initializers = + [ + { + _class = "C_INIT_CreateWithinBox" + m_vecMin = + { + m_nType = "PVEC_TYPE_LITERAL" + m_vLiteralValue = [ 15.0, 0.0, 0.0 ] + m_LiteralColor = [ 0, 0, 0 ] + m_NamedValue = "" + m_bFollowNamedValue = false + m_nVectorAttribute = 6 + m_vVectorAttributeScale = [ 1.0, 1.0, 1.0 ] + m_nControlPoint = 0 + m_nDeltaControlPoint = 0 + m_vCPValueScale = [ 1.0, 1.0, 1.0 ] + m_vCPRelativePosition = [ 0.0, 0.0, 0.0 ] + m_vCPRelativeDir = [ 1.0, 0.0, 0.0 ] + m_FloatComponentX = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_FloatComponentY = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_FloatComponentZ = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_FloatInterp = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_flInterpInput0 = 0.0 + m_flInterpInput1 = 1.0 + m_vInterpOutput0 = [ 0.0, 0.0, 0.0 ] + m_vInterpOutput1 = [ 1.0, 1.0, 1.0 ] + m_Gradient = + { + m_Stops = [ ] + } + m_vRandomMin = [ 0.0, 0.0, 0.0 ] + m_vRandomMax = [ 0.0, 0.0, 0.0 ] + } + m_vecMax = + { + m_nType = "PVEC_TYPE_LITERAL" + m_vLiteralValue = [ 15.0, 0.0, 0.0 ] + m_LiteralColor = [ 0, 0, 0 ] + m_NamedValue = "" + m_bFollowNamedValue = false + m_nVectorAttribute = 6 + m_vVectorAttributeScale = [ 1.0, 1.0, 1.0 ] + m_nControlPoint = 0 + m_nDeltaControlPoint = 0 + m_vCPValueScale = [ 1.0, 1.0, 1.0 ] + m_vCPRelativePosition = [ 0.0, 0.0, 0.0 ] + m_vCPRelativeDir = [ 1.0, 0.0, 0.0 ] + m_FloatComponentX = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_FloatComponentY = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_FloatComponentZ = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_FloatInterp = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_flInterpInput0 = 0.0 + m_flInterpInput1 = 1.0 + m_vInterpOutput0 = [ 0.0, 0.0, 0.0 ] + m_vInterpOutput1 = [ 1.0, 1.0, 1.0 ] + m_Gradient = + { + m_Stops = [ ] + } + m_vRandomMin = [ 0.0, 0.0, 0.0 ] + m_vRandomMax = [ 0.0, 0.0, 0.0 ] + } + m_bLocalSpace = true + }, + { + _class = "C_INIT_InitFloat" + m_InputValue = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 60.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 1.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + }, + ] + m_Operators = + [ + { + _class = "C_OP_PositionLock" + m_bLockRot = true + }, + { + _class = "C_OP_RemapTransformOrientationToRotations" + }, + { + _class = "C_OP_SetFloat" + m_InputValue = + { + m_nType = "PF_TYPE_CONCURRENT_DEF_COUNT" + m_nMapType = "PF_MAP_TYPE_NOTCHED" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_bReverseOrder = false + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_strSnapshotSubset = "" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_nOutputField = 7 + }, + { + _class = "C_OP_AlphaDecay" + }, + ] + m_Renderers = + [ + { + _class = "C_OP_RenderStandardLight" + m_nLightType = "PARTICLE_LIGHT_TYPE_SPOT" + m_flTheta = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 0.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_flPhi = + { + m_nType = "PF_TYPE_LITERAL" + m_nMapType = "PF_MAP_TYPE_DIRECT" + m_flLiteralValue = 35.0 + m_NamedValue = "" + m_nControlPoint = 0 + m_nScalarAttribute = 3 + m_nVectorAttribute = 6 + m_nVectorComponent = 0 + m_flRandomMin = 0.0 + m_flRandomMax = 1.0 + m_bHasRandomSignFlip = false + m_nRandomSeed = -1 + m_nRandomMode = "PF_RANDOM_MODE_CONSTANT" + m_flLOD0 = 0.0 + m_flLOD1 = 0.0 + m_flLOD2 = 0.0 + m_flLOD3 = 0.0 + m_nNoiseInputVectorAttribute = 0 + m_flNoiseOutputMin = 0.0 + m_flNoiseOutputMax = 1.0 + m_flNoiseScale = 0.1 + m_vecNoiseOffsetRate = [ 0.0, 0.0, 0.0 ] + m_flNoiseOffset = 0.0 + m_nNoiseOctaves = 1 + m_nNoiseTurbulence = "PF_NOISE_TURB_NONE" + m_nNoiseType = "PF_NOISE_TYPE_PERLIN" + m_nNoiseModifier = "PF_NOISE_MODIFIER_NONE" + m_flNoiseTurbulenceScale = 1.0 + m_flNoiseTurbulenceMix = 0.5 + m_flNoiseImgPreviewScale = 1.0 + m_bNoiseImgPreviewLive = true + m_flNoCameraFallback = 0.0 + m_bUseBoundsCenter = false + m_nInputMode = "PF_INPUT_MODE_CLAMPED" + m_flMultFactor = 1.0 + m_flInput0 = 0.0 + m_flInput1 = 1.0 + m_flOutput0 = 0.0 + m_flOutput1 = 1.0 + m_flNotchedRangeMin = 0.0 + m_flNotchedRangeMax = 1.0 + m_flNotchedOutputOutside = 0.0 + m_flNotchedOutputInside = 1.0 + m_nRoundType = "PF_ROUND_TYPE_NEAREST" + m_nBiasType = "PF_BIAS_TYPE_STANDARD" + m_flBiasParameter = 0.0 + m_Curve = + { + m_spline = [ ] + m_tangents = [ ] + m_vDomainMins = [ 0.0, 0.0 ] + m_vDomainMaxs = [ 0.0, 0.0 ] + } + } + m_nAttenuationStyle = "LIGHT_STYLE_NEW" + m_nMaxAllowed = 1 + m_Notes = "you're so skibidi" + }, + ] +} \ No newline at end of file diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 893392d11..f52762187 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -13,7 +13,7 @@ cs2f_hide_enable 0 // Whether to enable hide (WARNING: randomly crashes cli cs2f_votemanager_enable 0 // Whether to enable votemanager features such as map vote fix, nominations, RTV and extends cs2f_trigger_timer_enable 0 // Whether to process countdown messages said by Console (e.g. Hold for 10 seconds) and append the round time where the countdown resolves cs2f_block_nav_lookup 0 // Whether to block navigation mesh lookup, improves server performance but breaks bot navigation -cs2f_flashlight_enable 0 // Whether to enable flashlights +cs2f_flashlight_enable 0 // Whether to enable flashlights (0=disabled, 1=light_barn flashlight, limited vertical movement, 2=particle flashlight, no cvar customization) cs2f_infinite_reserve_ammo 0 // Whether to enable infinite reserve ammo on weapons cs2f_disable_subtick_move 0 // Whether to disable subtick movement cs2f_disable_subtick_shooting 0 // Whether to disable subtick shooting, experimental (WARNING: add "log_flags Shooting +DoNotEcho" to your cfg to prevent console spam on every shot fired) @@ -40,7 +40,8 @@ cs2f_flashlight_brightness 1.0 // How bright should flashlights be cs2f_flashlight_distance 54 // How far flashlights should be from the player's head (the default is such that an equipped awp doesn't block the light if shadows are enabled) cs2f_flashlight_angle 45.0 // How wide should the flashlight be in degrees cs2f_flashlight_color "255 255 255 0" // What color to use for flashlights -cs2f_flashlight_attachment axis_of_intent // Which attachment to parent a flashlight to. If the player model is not properly setup, you might have to use clip_limit here instead +cs2f_flashlight_attachment "clip_limit" // Which attachment to parent a flashlight to +cs2f_flashlight_particle "particles/cs2fixes/simple_flashlight.vpcf" // Path to flashlight particle // Damage block settings cs2f_block_molotov_self_dmg 0 // Whether to block self-damage from molotovs diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 9f4ef075d..4bd473678 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -163,13 +163,15 @@ void ZEPlayer::SetHideDistance(int distance) g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), HIDE_DISTANCE_PREF_KEY_NAME, distance); } +CConVar g_cvarFlashLightEnable("cs2f_flashlight_enable", FCVAR_NONE, "Whether to enable flashlights (0=disabled, 1=light_barn flashlight, limited vertical movement, 2=particle flashlight, no cvar customization)", false); CConVar g_cvarFlashLightShadows("cs2f_flashlight_shadows", FCVAR_NONE, "Whether to enable flashlight shadows", true); CConVar g_cvarFlashLightTransmitOthers("cs2f_flashlight_transmit_others", FCVAR_NONE, "Whether to transmit other player's flashlights, recommended to have shadows off for this", false); CConVar g_cvarFlashLightBrightness("cs2f_flashlight_brightness", FCVAR_NONE, "How bright should flashlights be", 1.0f); CConVar g_cvarFlashLightDistance("cs2f_flashlight_distance", FCVAR_NONE, "How far flashlights should be from the player's head", 54.0f); // The minimum distance such that an awp wouldn't block the light CConVar g_cvarFlashLightAngle("cs2f_flashlight_angle", FCVAR_NONE, "How wide should the flashlight be in degrees", 45.0f); CConVar g_cvarFlashLightColor("cs2f_flashlight_color", FCVAR_NONE, "What color to use for flashlights", Color(255, 255, 255)); -CConVar g_cvarFlashLightAttachment("cs2f_flashlight_attachment", FCVAR_NONE, "Which attachment to parent a flashlight to. If the player model is not properly setup, you might have to use clip_limit here instead", "axis_of_intent"); +CConVar g_cvarFlashLightAttachment("cs2f_flashlight_attachment", FCVAR_NONE, "Which attachment to parent a flashlight to", "clip_limit"); +CConVar g_cvarFlashLightParticle("cs2f_flashlight_particle", FCVAR_NONE, "Path to flashlight particle", "particles/cs2fixes/simple_flashlight.vpcf"); void TeleportFlashLight(CCSPlayerPawn* pPawn, CBaseEntity* pLight, float flDistance = -1.f, QAngle angOverride = vec3_angle) { @@ -239,6 +241,14 @@ void ZEPlayer::ToggleFlashLight() CSingleRecipientFilter filter(GetPlayerSlot()); pController->EmitSoundFilter(filter, "HudChat.Message"); + // particle flashlight + if (g_cvarFlashLightEnable.Get() == 2) + { + pController->DispatchParticle(g_cvarFlashLightParticle.Get().String(), &filter); + return; + } + + // light_barn flashlight if (!GetFlashLight()) SpawnFlashLight(); @@ -286,6 +296,7 @@ bool ZEPlayer::IsFlooding() void PrecacheBeaconParticle(IEntityResourceManifest* pResourceManifest) { pResourceManifest->AddResource(g_cvarBeaconParticle.Get().String()); + pResourceManifest->AddResource(g_cvarFlashLightParticle.Get().String()); } void ZEPlayer::StartBeacon(Color color, ZEPlayerHandle hGiver /* = 0*/) @@ -941,8 +952,6 @@ void CPlayerManager::CheckInfractions() g_pAdminSystem->SaveInfractions(); } -CConVar g_cvarFlashLightEnable("cs2f_flashlight_enable", FCVAR_NONE, "Whether to enable flashlights", false); - void CPlayerManager::FlashLightThink() { if (!g_cvarFlashLightEnable.Get() || !GetGlobals()) From 3180a4491dcfc37821270643a09462438bb42dde Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 23 Apr 2026 22:30:54 -0400 Subject: [PATCH 22/32] Attempt to fix lag/client crashes with a ParticleManager msg blocker Co-authored-by: tilgep --- cfg/cs2fixes/cs2fixes.cfg | 1 + src/cs2fixes.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index f52762187..d7f196180 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -24,6 +24,7 @@ cs2f_prevent_using_players 0 // Whether to prevent +use from hitting players ( cs2f_map_steamids_enable 0 // Whether to make Steam ID's available to maps cs2f_fix_game_bans 0 // Whether to fix CS2 game bans spreading to all new joining players cs2f_free_armor 0 // Whether kevlar (1+) and/or helmet (2) are given automatically +cs2f_block_particle_msgs 0 // Whether to block CUserMsg_ParticleManager messages to fix lag/crashes, experimental cs2f_beacon_particle "particles/cs2fixes/admin_beacon.vpcf" // .vpcf file to be precached and used for player beacon cs2f_motd_url "" // Server MOTD URL, shows up as a "Server Website" button in scoreboard diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 2cca4031d..43c6d3cfd 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -661,6 +661,8 @@ void CS2Fixes::Hook_GameServerSteamAPIActivated() RETURN_META(MRES_IGNORED); } +CConVar g_cvarBlockParticleMsgs("cs2f_block_particle_msgs", FCVAR_NONE, "Whether to block CUserMsg_ParticleManager messages to fix lag/crashes, experimental", false); + void CS2Fixes::Hook_PostEvent(CSplitScreenSlot nSlot, bool bLocalOnly, int nClientCount, const uint64* clients, INetworkMessageInternal* pEvent, const CNetMessage* pData, unsigned long nSize, NetChannelBufType_t bufType) { @@ -789,6 +791,13 @@ void CS2Fixes::Hook_PostEvent(CSplitScreenSlot nSlot, bool bLocalOnly, int nClie *(uint64*)clients &= ~silenceSoundMask; } } + else if (info->m_MessageId == UM_ParticleManager) + { + // These messages were previously unused, but recently started being used for weapon particles in the AG2 update + // Unfortunately, this new system seems extremely unoptimized for 64 players, and was causing severe performance issues & vector overflow client crashes + if (g_cvarBlockParticleMsgs.Get()) + *(uint64*)clients = 0; + } } void CS2Fixes::AllPluginsLoaded() From 1e85ae3d92f948a2061fb22e339de6487061fc48 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 24 Apr 2026 19:48:13 -0400 Subject: [PATCH 23/32] Add cvar for disabling map SetModel usage Can be used in map configs when a map is still using AG1 playermodels, or just disable globally in plugin cfg --- cfg/cs2fixes/cs2fixes.cfg | 1 + gamedata/cs2fixes.jsonc | 15 +++++--- src/addresses.h | 2 +- src/cs2_sdk/entity/cbasemodelentity.h | 4 +-- src/detours.cpp | 51 +++++++++++++++++++++------ src/detours.h | 6 ++-- 6 files changed, 59 insertions(+), 20 deletions(-) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index d7f196180..24f28e97a 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -25,6 +25,7 @@ cs2f_map_steamids_enable 0 // Whether to make Steam ID's available to maps cs2f_fix_game_bans 0 // Whether to fix CS2 game bans spreading to all new joining players cs2f_free_armor 0 // Whether kevlar (1+) and/or helmet (2) are given automatically cs2f_block_particle_msgs 0 // Whether to block CUserMsg_ParticleManager messages to fix lag/crashes, experimental +cs2f_disable_setmodel 0 // Whether to disable SetModel usage from maps (custom input, cs_script function) cs2f_beacon_particle "particles/cs2fixes/admin_beacon.vpcf" // .vpcf file to be precached and used for player beacon cs2f_motd_url "" // Server MOTD URL, shows up as a "Server Website" button in scoreboard diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 26e8a32b4..45b8ae980 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -160,13 +160,20 @@ "windows": "48 89 5C 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 4C 8B 2D", "linux": "55 48 89 E5 41 57 49 89 D7 41 56 41 55 49 89 FD 41 54 4D 89 C4" }, - // Search "Changes's player's model", look for a function containing 'models/%s.vmdl'. Below V_snprintf is the one - // This matches 2 functions, however they're literally identical + // Has "SetModel" string, but is also referenced by cs_script registration function using the same string + "CS_Script_SetModel": + { + "library": "server", + "windows": "40 55 56 41 56 48 83 EC ? 48 8B F1 BA ? ? ? ? 8B 0D ? ? ? ? FF 15 ? ? ? ? 4C 8D 35 ? ? ? ? 84 C0 74 ? 8B 0D ? ? ? ? 4C 8D 0D ? ? ? ? 4C 8D 05 ? ? ? ? 4C 89 74 24 ? BA ? ? ? ? FF 15 ? ? ? ? 48 89 9C 24 ? ? ? ? 48 89 BC 24 ? ? ? ? E8 ? ? ? ? 48 8B D0 48 8D 4C 24 ? 48 8B E8 E8 ? ? ? ? E8 ? ? ? ? 48 85 C0 75 ? 48 8D 15 ? ? ? ? E9 ? ? ? ? 48 8D 94 24 ? ? ? ? 48 8B C8 E8 ? ? ? ? 48 8B 5E ? 48 83 EB ? 48 8B CB E8 ? ? ? ? 83 F8 ? 0F 85 ? ? ? ? 48 8B 0B 48 8B 41 ? 0F B7 40 ? 3D ? ? ? ? 74 ? 05 ? ? ? ? 3D ? ? ? ? 76 ? 33 D2 48 8B CB E8 ? ? ? ? EB ? 48 8B 41 ? 48 8D 0D ? ? ? ? 48 3B C1 0F 85 ? ? ? ? 48 8B 0B 48 8B 41 ? 0F B7 40 ? 3D ? ? ? ? 74 ? 05 ? ? ? ? 3D ? ? ? ? 76 ? BA ? ? ? ? 48 8B CB E8 ? ? ? ? EB ? 48 8B 41 ? 48 85 C0 0F 84 ? ? ? ? 33 DB 83 38 ? 75 ? 8B 48 ? 83 F9 ? 74 ? 4C 8B 05 ? ? ? ? 4D 85 C0 74 ? 83 F9 ? 74 ? 8B C1 25 ? ? ? ? 8B D0 48 C1 E8 ? 4D 8B 0C C0 4D 85 C9 74 ? 81 E2 ? ? ? ? 48 6B C2 ? 49 03 C1 74 ? 39 48 ? 48 0F 45 C3 EB ? 48 8B C3 48 85 C0 74 ? 48 8B 08 EB ? 48 8B CB 4C 8D 0D ? ? ? ? 89 5C 24 ? 4C 8D 05 ? ? ? ? 33 D2 E8 ? ? ? ? 48 8B F8 48 85 C0 75 ? 48 8D 15 ? ? ? ? E9 ? ? ? ? 83 7E ? ? 7D ? 8B 0D ? ? ? ? BA ? ? ? ? FF 15 ? ? ? ? 84 C0 0F 84 ? ? ? ? 8B 0D", + "linux": "55 BE ? ? ? ? 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 83 EC ? 4C 8D 3D ? ? ? ? 41 8B 3F E8 ? ? ? ? 84 C0 0F 85 ? ? ? ? E8 ? ? ? ? 4C 8D 6D ? 4C 89 EF 48 89 C6 49 89 C4 E8 ? ? ? ? E8 ? ? ? ? 48 89 C7 48 85 C0 0F 84 ? ? ? ? E8 ? ? ? ? 49 89 C6 48 8B 43 ? 48 8D 78 ? E8 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 83 38 ? 0F 85 ? ? ? ? 8B 48 ? 83 F9 ? 0F 84 ? ? ? ? 48 8B 35 ? ? ? ? 48 85 F6 0F 84 ? ? ? ? 83 F9 ? 0F 84 ? ? ? ? 0F B7 40 ? 48 89 C2 48 C1 EA ? 83 E2 ? 48 8B 14 D6 48 85 D2 0F 84 ? ? ? ? 25 ? ? ? ? 48 6B C0 ? 48 01 D0 3B 48 ? 0F 85 ? ? ? ? 48 8B 38 48 85 FF 0F 84 ? ? ? ? 48 8D 15" + }, + // Called by CS_Script_SetModel + // This has two identical functions, but because we're detouring for cs_script, we must go beyond function boundaries for a unique signature "CBaseModelEntity_SetModel": { "library": "server", - "windows": "40 53 48 83 EC ? 48 8B D9 4C 8B C2 48 8B 0D ? ? ? ? 48 8D 54 24 ? 48 8B 01 FF 50 ? 48 8B 54 24", - "linux": "55 48 89 E5 53 48 89 FB 48 83 EC ? 48 8D 05 ? ? ? ? 48 8B 38 48 8B 07 FF 50 ? 48 89 DF" + "windows": "40 53 48 83 EC ? 48 8B D9 4C 8B C2 48 8B 0D ? ? ? ? 48 8D 54 24 ? 48 8B 01 FF 50 ? 48 8B 54 24 ? 48 8B CB E8 ? ? ? ? 48 83 C4 ? 5B C3 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC 48 89 5C 24", + "linux": "55 48 89 E5 53 48 89 FB 48 83 EC ? 48 8D 05 ? ? ? ? 48 8B 38 48 8B 07 FF 50 ? 48 89 DF 48 8B 5D ? C9 48 89 C6 E9 ? ? ? ? CC CC CC CC 55" }, "CGameRules_TerminateRound": { diff --git a/src/addresses.h b/src/addresses.h index 622d068d2..04c8ccb88 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -80,7 +80,7 @@ namespace addresses inline void(FASTCALL* SetGravityScale)(CBaseEntity*, float); inline void(FASTCALL* CCSPlayerController_SwitchTeam)(CCSPlayerController* pController, uint32 team); inline void(FASTCALL* CBasePlayerController_SetPawn)(CBasePlayerController* pController, CCSPlayerPawn* pPawn, bool a3, bool a4, bool a5, bool a6); - inline void(FASTCALL* CBaseModelEntity_SetModel)(CBaseModelEntity* pModel, const char* szModel); + inline void(FASTCALL* CBaseModelEntity_SetModel)(CBaseModelEntity* pModel, const char* pszModel); inline void(FASTCALL* UTIL_Remove)(CEntityInstance*); inline void(FASTCALL* CEntitySystem_AddEntityIOEvent)(CEntitySystem* pEntitySystem, CEntityInstance* pTarget, const char* pszInput, diff --git a/src/cs2_sdk/entity/cbasemodelentity.h b/src/cs2_sdk/entity/cbasemodelentity.h index bd3abae65..6463f2624 100644 --- a/src/cs2_sdk/entity/cbasemodelentity.h +++ b/src/cs2_sdk/entity/cbasemodelentity.h @@ -34,9 +34,9 @@ class CBaseModelEntity : public CBaseEntity SCHEMA_FIELD(float, m_flDissolveStartTime) SCHEMA_FIELD(Vector, m_vecViewOffset) - void SetModel(const char* szModel) + void SetModel(const char* pszModel) { - addresses::CBaseModelEntity_SetModel(this, szModel); + addresses::CBaseModelEntity_SetModel(this, pszModel); } void SetCollisionGroup(StandardCollisionGroups_t nCollisionGroup) diff --git a/src/detours.cpp b/src/detours.cpp index 14ef1255b..2c574c9e0 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -84,6 +84,8 @@ DECLARE_DETOUR(CBasePlayerPawn_GetEyeAngles, Detour_CBasePlayerPawn_GetEyeAngles DECLARE_DETOUR(CBaseFilter_InputTestActivator, Detour_CBaseFilter_InputTestActivator); DECLARE_DETOUR(GameSystem_Think_CheckSteamBan, Detour_GameSystem_Think_CheckSteamBan); DECLARE_DETOUR(CCSPlayer_ItemServices_CanAcquire, Detour_CCSPlayer_ItemServices_CanAcquire); +DECLARE_DETOUR(CS_Script_SetModel, Detour_CS_Script_SetModel); +DECLARE_DETOUR(CBaseModelEntity_SetModel, Detour_CBaseModelEntity_SetModel); CConVar g_cvarBlockMolotovSelfDmg("cs2f_block_molotov_self_dmg", FCVAR_NONE, "Whether to block self-damage from molotovs", false); CConVar g_cvarBlockAllDamage("cs2f_block_all_dmg", FCVAR_NONE, "Whether to block all damage to players", false); @@ -405,6 +407,24 @@ void FASTCALL Detour_CCSPlayer_WeaponServices_EquipWeapon(CCSPlayer_WeaponServic return CCSPlayer_WeaponServices_EquipWeapon(pWeaponServices, pPlayerWeapon); } +CConVar g_cvarDisableSetModel("cs2f_disable_setmodel", FCVAR_NONE, "Whether to disable SetModel usage from maps (custom input, cs_script function)", false); + +bool PrepareMapSetModel(CBaseModelEntity* pModel) +{ + if (!pModel->IsPawn()) + return true; + + if (g_cvarDisableSetModel.Get()) + return false; + + // Player color may have been changed by zclass/server customization, so reset it first + // This also means if maps want to change player color, it needs to be done after the SetModel call + int originalAlpha = pModel->m_clrRender().a(); + pModel->m_clrRender = Color(255, 255, 255, originalAlpha); + + return true; +} + bool FASTCALL Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, CUtlSymbolLarge* pInputName, CEntityInstance* pActivator, CEntityInstance* pCaller, variant_t* value, int nOutputID, void* a7, void* a8) { VPROF_SCOPE_BEGIN("Detour_CEntityIdentity_AcceptInput"); @@ -473,18 +493,9 @@ bool FASTCALL Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, CUtlSym { if (const auto pModelEntity = reinterpret_cast(pThis->m_pInstance)->AsBaseModelEntity()) { - if ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString) - { - // Player color may have been changed by zclass/server customization, so reset it first - // This also means if maps want to change player color, it needs to be done after the SetModel input - if (pModelEntity->IsPawn()) - { - int originalAlpha = pModelEntity->m_clrRender().a(); - pModelEntity->m_clrRender = Color(255, 255, 255, originalAlpha); - } - + if ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString && PrepareMapSetModel(pModelEntity)) pModelEntity->SetModel(value->m_pszString); - } + return true; } } @@ -820,6 +831,24 @@ AcquireResult FASTCALL Detour_CCSPlayer_ItemServices_CanAcquire(CCSPlayer_ItemSe return CCSPlayer_ItemServices_CanAcquire(pItemServices, pEconItem, iAcquireMethod, unk4); } +bool g_bInScriptSetModel = false; + +void FASTCALL Detour_CS_Script_SetModel(uint64_t unk1) +{ + g_bInScriptSetModel = true; + CS_Script_SetModel(unk1); + g_bInScriptSetModel = false; +} + +void FASTCALL Detour_CBaseModelEntity_SetModel(CBaseModelEntity* pModel, const char* pszModel) +{ + if (!g_bInScriptSetModel) + return CBaseModelEntity_SetModel(pModel, pszModel); + + if (PrepareMapSetModel(pModel)) + return CBaseModelEntity_SetModel(pModel, pszModel); +} + bool InitDetours(CGameConfig* gameConfig) { bool success = true; diff --git a/src/detours.h b/src/detours.h index 4aa20ce59..f694ae1d8 100644 --- a/src/detours.h +++ b/src/detours.h @@ -1,4 +1,4 @@ -/** +/** * ============================================================================= * CS2Fixes * Copyright (C) 2023-2026 Source2ZE @@ -112,4 +112,6 @@ QAngle FASTCALL Detour_CBasePlayerPawn_GetEyeAngles(CBasePlayerPawn*); #endif void FASTCALL Detour_CBaseFilter_InputTestActivator(CBaseEntity* pThis, InputData_t& inputdata); void FASTCALL Detour_GameSystem_Think_CheckSteamBan(); -AcquireResult FASTCALL Detour_CCSPlayer_ItemServices_CanAcquire(CCSPlayer_ItemServices* pItemServices, CEconItemView* pEconItem, AcquireMethod iAcquireMethod, uint64_t unk4); \ No newline at end of file +AcquireResult FASTCALL Detour_CCSPlayer_ItemServices_CanAcquire(CCSPlayer_ItemServices* pItemServices, CEconItemView* pEconItem, AcquireMethod iAcquireMethod, uint64_t unk4); +void FASTCALL Detour_CS_Script_SetModel(uint64_t unk1); +void FASTCALL Detour_CBaseModelEntity_SetModel(CBaseModelEntity* pModel, const char* pszModel); \ No newline at end of file From 8ca812bf51b5cbdf9eaf52ffb7687eacfc99590b Mon Sep 17 00:00:00 2001 From: Vauff Date: Sun, 26 Apr 2026 00:34:27 -0400 Subject: [PATCH 24/32] Fix broken cases of teleport angles on player pawns --- src/cs2_sdk/entity/cbaseentity.h | 4 ++-- src/cs2fixes.cpp | 29 +++++++++++++++++++++++++++++ src/cs2fixes.h | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/cs2_sdk/entity/cbaseentity.h b/src/cs2_sdk/entity/cbaseentity.h index ac017ca6b..c76556579 100644 --- a/src/cs2_sdk/entity/cbaseentity.h +++ b/src/cs2_sdk/entity/cbaseentity.h @@ -174,10 +174,10 @@ class CBaseEntity : public CEntityInstance Detour_CBaseEntity_TakeDamageOld(this, &info, 0); } - void Teleport(const Vector* position, const QAngle* angles, const Vector* velocity) + void Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity) { static int offset = g_GameConfig->GetOffset("Teleport"); - CALL_VIRTUAL(void, offset, this, position, angles, velocity); + CALL_VIRTUAL(void, offset, this, pPosition, pAngles, pVelocity); } void SetCollisionGroup(StandardCollisionGroups_t nCollisionGroup) diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 43c6d3cfd..808193c49 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -95,6 +95,7 @@ SH_DECL_MANUALHOOK2_void(PhysicsTouchShuffle, 0, 0, 0, CUtlVector SH_DECL_MANUALHOOK3_void(DropWeapon, 0, 0, 0, CBasePlayerWeapon*, Vector*, Vector*); SH_DECL_HOOK1_void(IServer, SetGameSpawnGroupMgr, SH_NOATTRIB, 0, IGameSpawnGroupMgr*); SH_DECL_HOOK2_void(CEntitySystem, Spawn, SH_NOATTRIB, 0, int, const EntitySpawnInfo_t*); +SH_DECL_MANUALHOOK3_void(Teleport, 0, 0, 0, const Vector*, const QAngle*, const Vector*); CS2Fixes g_CS2Fixes; IGameEventSystem* g_gameEventSystem = nullptr; @@ -117,6 +118,7 @@ int g_iPhysicsTouchShuffle = -1; int g_iWeaponServiceDropWeaponId = -1; int g_iSetGameSpawnGroupMgrId = -1; int g_iSpawnId = -1; +int g_iTeleportId = -1; double g_flUniversalTime = 0.0; float g_flLastTickedTime = 0.0f; @@ -276,6 +278,15 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool SH_MANUALHOOK_RECONFIGURE(OnTakeDamage_Alive, offset, 0, 0); g_iOnTakeDamageAliveId = SH_ADD_MANUALDVPHOOK(OnTakeDamage_Alive, pCCSPlayerPawnVTable, SH_MEMBER(this, &CS2Fixes::Hook_OnTakeDamage_Alive), false); + offset = g_GameConfig->GetOffset("Teleport"); + if (offset == -1) + { + snprintf(error, maxlen, "Failed to find Teleport\n"); + bRequiredInitLoaded = false; + } + SH_MANUALHOOK_RECONFIGURE(Teleport, offset, 0, 0); + g_iTeleportId = SH_ADD_MANUALDVPHOOK(Teleport, pCCSPlayerPawnVTable, SH_MEMBER(this, &CS2Fixes::Hook_Teleport), false); + const auto pCCSPlayer_MovementServicesVTable = modules::server->FindVirtualTable("CCSPlayer_MovementServices"); offset = g_GameConfig->GetOffset("CCSPlayer_MovementServices::CheckMovingGround"); if (offset == -1) @@ -430,6 +441,7 @@ bool CS2Fixes::Unload(char* error, size_t maxlen) SH_REMOVE_HOOK_ID(g_iCTriggerGravityPrecacheId); SH_REMOVE_HOOK_ID(g_iCTriggerGravityEndTouchId); SH_REMOVE_HOOK_ID(g_iSpawnId); + SH_REMOVE_HOOK_ID(g_iTeleportId); if (g_iSetGameSpawnGroupMgrId != -1) SH_REMOVE_HOOK_ID(g_iSetGameSpawnGroupMgrId); @@ -1204,6 +1216,23 @@ void CS2Fixes::Hook_SpawnPost(int nCount, const EntitySpawnInfo_t* pInfo) g_pMapMigrations->OnEntitySpawned(pInfo[i].m_pEntity->m_pInstance, pInfo[i].m_pKeyValues); } +void CS2Fixes::Hook_Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity) +{ + if (!pAngles) + RETURN_META(MRES_IGNORED); + + QAngle* pCastAngles = const_cast(pAngles); + + // Post-AG2, changing x or z angles on a playermodel will bug out, and never did anything pre-AG2 anyways + if (pCastAngles->x != 0.0f) + pCastAngles->x = 0.0f; + + if (pCastAngles->z != 0.0f) + pCastAngles->z = 0.0f; + + RETURN_META(MRES_HANDLED); +} + void* CS2Fixes::OnMetamodQuery(const char* iface, int* ret) { if (V_strcmp(iface, CS2FIXES_INTERFACE)) diff --git a/src/cs2fixes.h b/src/cs2fixes.h index ea5cad5fe..924b68650 100644 --- a/src/cs2fixes.h +++ b/src/cs2fixes.h @@ -95,6 +95,7 @@ class CS2Fixes : public ISmmPlugin, public IMetamodListener, public ICS2Fixes void Hook_GoToIntermission(bool bAbortedMatch); bool Hook_OnTakeDamage_Alive(CTakeDamageResult* pDamageResult); void Hook_PhysicsTouchShuffle(CUtlVector* pList, bool unknown); + void Hook_Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity); #ifdef PLATFORM_WINDOWS Vector* Hook_GetEyePosition(Vector*); QAngle* Hook_GetEyeAngles(QAngle*); From 48cbc78bd1ff7668f60d530deeb54b424078834c Mon Sep 17 00:00:00 2001 From: Vauff Date: Mon, 27 Apr 2026 03:06:33 -0400 Subject: [PATCH 25/32] Update flashlight particle Co-authored-by: Connor <34824423+EasterLee@users.noreply.github.com> --- .../cs2fixes/simple_flashlight.vpcf_c | Bin 3514 -> 3530 bytes .../particles/cs2fixes/simple_flashlight.vpcf | 21 ++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/assets/particles/cs2fixes/simple_flashlight.vpcf_c b/assets/particles/cs2fixes/simple_flashlight.vpcf_c index 137c39bb770de6ebe9e16778110ddc04a04b96a1..7668d9828b7b5a6977ec655f85951260032d96ce 100644 GIT binary patch delta 923 zcmZ9J%Wo4$9LK-2_HNd(&91#Jb}-;POk&bNoPZP|K+eN1;gQ6`NeC^Fmkqd3Z?Iz^ z5FUYm1Sis!XvC!#khpL_sZt3Ei31W+uAC|r@gGD;29%rmF6ybH`ONn_znNL>eCJho zEiBfSM9}MZ0?D4?o;dZ|(vF09vXqO6uP^VdOU+u>m;DEjsR5wI0fFvX+A%!xP`qSQ z8!9gAiDT6oa&8-Zssi@jCDQKzT5$%^MnH10@W0m2D-P?G zbG)@<>Tn^6iCnK)E@b`qq)eNI*`j$dZRQKJeP-co{#>~@nT1GLd*u=F!g?q-)y4bL z9e<;HsF=^yp(8byTSjNvEV+dBPTr|+7t@o4oLMe~AqL@W{9OqL(jqVuM(03JI)cgM z;p3^k;f0lUWl<Fd#u+r^O8fh_NxP8ZsmdcTtpA5de392s^+qoGs`W-Tz$!` zFI~t_<+FL*XI829qt=PqmM%AMBROHnDl#4PPA7sv9hwR`B4P+(0!F(ILkb}5h$2`M zMW8(dYqhrX)_W!jJ3TvhcMMbCL+8gUn>1E*;v;@y5N3%V$mS^E5tYp$`Z}_OgvnN7 zhr69r*&@{XMHmgYQBn9%Xd*m|9i-XrEpb>ePIi)39q)gnwvkJ#;VJ zVj<%Z#;^)&gnpEq(2*IVo{Wk=ey09HPSuOx>5%9?LmwAaX`DJiCdm|;&WfrW$%gDP z_kBETj}_${7tfPC`ITHC7o+&|H)_G|=3A$Ir@xFD9pjf+E%uA3mJ}}SfOuw<_%E|8 zmOU^os|a3c6UNmx5t*BnJ{#ALd6{YEI@jkt_;`bQlh}8d_!o|_F=if=TE?qg60tGx;H8LJnZ> dSwyqXy(Y;CM11quBCkN}LU=~e6?|B)egh)qtk?hm delta 918 zcmZ9K&rcgi6vw}B*KJBtY?n_G=Jxw-6oF+Y73)Food1nr4k<;;owSfUq8shP2SHq(sW_*<1o2imYw9#Roy$1ILI5-h*%V$i&~T9&mILS;i6(4JU-{%}JT~sU8B({&^}|FV zbJ;28(gpEj?S}NHEaKV-&A$=aYic{EnbDWhu`83tx>F42Gr@urEZoh`WYbyR_A_=V z-qS5ouJAzBEJ=o?Xh`;QF3U*zS$lLC8Wfw_(d3s*SW*N0HLHLLyLJ#HzIXLq*s6L~ z$25`UZbyrUUtIS7=QkHk#>dn%7Q-gugAlAnoyzs1+ubyF%;Q6@+FP)K8z`%M4rpP{ zFd?RuX^TLFS=*VjCdyI=C+C<>riQu4Q)sW#(R_C~3o>^e3 zX5L}$hVa!Q>k_bu+zYw-U)z>rBDKubl|ialdEQ5XC#yQFq6YuHPO{cI$-cks{@Ysr zU1#T#4|x5dj$bxdA2E-a%>}7qZ}FGK6P`U~KCgH~+tqtMI{f7>q2;?vCVGD5uw?9@ z)l0SL+KLWfzfN^4rs(io8;RDbs&A}%t&9;g8vS^F+E+h>ni!0K@tf)SNb)Ih*!6KV hqfa{TQPrm~R-{ut_km Date: Thu, 30 Apr 2026 23:08:34 -0400 Subject: [PATCH 26/32] Change GoToIntermission virtual hook to a detour VTable hook no longer fires, because the function gets called directly after the AG2 update Previously we avoided a detour due to a lot of signature instability in updates, however it looks like things have stabilized, so hopefully this won't be an issue again --- gamedata/cs2fixes.jsonc | 12 ++++++----- src/cs2_sdk/entity/cbaseplayercontroller.h | 4 ++-- src/cs2_sdk/entity/ctakedamageinfo.h | 8 +++---- src/cs2fixes.cpp | 25 ---------------------- src/cs2fixes.h | 1 - src/detours.cpp | 15 ++++++++++++- src/detours.h | 4 +++- 7 files changed, 30 insertions(+), 39 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 45b8ae980..ef4c30731 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -387,6 +387,13 @@ "library": "server", "windows": "75 ? 48 8B 03 48 8B CB FF 90 ? ? ? ? 84 C0 74 ? 48 8D 05", "linux": "75 ? 48 8B 03 48 8D 15 ? ? ? ? 48 8B 80 ? ? ? ? 48 39 D0 75 ? 48 83 C4" + }, + // "Going to intermission...\n" + "CCSGameRules_GoToIntermission": + { + "library": "server", + "windows": "48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 4C 8B E9", + "linux": "55 31 C0 48 89 E5 41 57 41 56 41 55 41 54 41 89 F4" } }, "Offsets": @@ -485,11 +492,6 @@ "windows": 26, "linux": 27 }, - "CCSGameRules_GoToIntermission": - { - "windows": 129, - "linux": 130 - }, "CheckTransmitPlayerSlot": { "windows": 576, diff --git a/src/cs2_sdk/entity/cbaseplayercontroller.h b/src/cs2_sdk/entity/cbaseplayercontroller.h index f31248c26..61e9f1afa 100644 --- a/src/cs2_sdk/entity/cbaseplayercontroller.h +++ b/src/cs2_sdk/entity/cbaseplayercontroller.h @@ -51,10 +51,10 @@ class CBasePlayerController : public CBaseEntity // - An observer pawn if spectating // - A bot pawn if controlling one CBasePlayerPawn* GetPawn() { return m_hPawn.Get(); } - std::string GetPlayerName() + std::string GetPlayerName() { std::string strName = m_iszPlayerName(); - + // Ignore space that might be added by clan tag name swap trick if (!strName.empty() && strName.back() == ' ') strName.pop_back(); diff --git a/src/cs2_sdk/entity/ctakedamageinfo.h b/src/cs2_sdk/entity/ctakedamageinfo.h index 1062d270a..389a0bded 100644 --- a/src/cs2_sdk/entity/ctakedamageinfo.h +++ b/src/cs2_sdk/entity/ctakedamageinfo.h @@ -134,10 +134,10 @@ class CTakeDamageInfo uint8_t m_nUnknown2[0x58]; // 0x88 | 136 public: - void* m_hScriptInstance; // 0xe0 | 224 - AttackerInfo_t m_AttackerInfo; // 0xe8 | 232 - CUtlLeanVector m_DestructibleHitGroupRequests; // 0x100 | 256 CUtlLeanVector - bool m_bInTakeDamageFlow; // 0x110 | 272 + void* m_hScriptInstance; // 0xe0 | 224 + AttackerInfo_t m_AttackerInfo; // 0xe8 | 232 + CUtlLeanVector m_DestructibleHitGroupRequests; // 0x100 | 256 CUtlLeanVector + bool m_bInTakeDamageFlow; // 0x110 | 272 private: [[maybe_unused]] int32_t m_nUnknown4; // 0x11c | 284 diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 808193c49..671ee996f 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -90,7 +90,6 @@ SH_DECL_MANUALHOOK2_void(CreateWorkshopMapGroup, 0, 0, 0, const char*, const CUt SH_DECL_MANUALHOOK1(OnTakeDamage_Alive, 0, 0, 0, bool, CTakeDamageResult*); SH_DECL_MANUALHOOK1_void(CheckMovingGround, 0, 0, 0, double); SH_DECL_HOOK2(IGameEventManager2, LoadEventsFromFile, SH_NOATTRIB, 0, int, const char*, bool); -SH_DECL_MANUALHOOK1_void(GoToIntermission, 0, 0, 0, bool); SH_DECL_MANUALHOOK2_void(PhysicsTouchShuffle, 0, 0, 0, CUtlVector*, bool); SH_DECL_MANUALHOOK3_void(DropWeapon, 0, 0, 0, CBasePlayerWeapon*, Vector*, Vector*); SH_DECL_HOOK1_void(IServer, SetGameSpawnGroupMgr, SH_NOATTRIB, 0, IGameSpawnGroupMgr*); @@ -113,7 +112,6 @@ int g_iCreateWorkshopMapGroupId = -1; int g_iOnTakeDamageAliveId = -1; int g_iCheckMovingGroundId = -1; int g_iLoadEventsFromFileId = -1; -int g_iGoToIntermissionId = -1; int g_iPhysicsTouchShuffle = -1; int g_iWeaponServiceDropWeaponId = -1; int g_iSetGameSpawnGroupMgrId = -1; @@ -330,17 +328,6 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool return false; } - auto pCCSGameRulesVTable = modules::server->FindVirtualTable("CCSGameRules"); - - offset = g_GameConfig->GetOffset("CCSGameRules_GoToIntermission"); - if (offset == -1) - { - snprintf(error, maxlen, "Failed to find CCSGameRules::GoToIntermission\n"); - bRequiredInitLoaded = false; - } - SH_MANUALHOOK_RECONFIGURE(GoToIntermission, offset, 0, 0); - g_iGoToIntermissionId = SH_ADD_MANUALDVPHOOK(GoToIntermission, pCCSGameRulesVTable, SH_MEMBER(this, &CS2Fixes::Hook_GoToIntermission), false); - Message("All hooks started!\n"); UnlockConVars(); @@ -435,7 +422,6 @@ bool CS2Fixes::Unload(char* error, size_t maxlen) SH_REMOVE_HOOK_ID(g_iCheckMovingGroundId); SH_REMOVE_HOOK_ID(g_iPhysicsTouchShuffle); SH_REMOVE_HOOK_ID(g_iWeaponServiceDropWeaponId); - SH_REMOVE_HOOK_ID(g_iGoToIntermissionId); SH_REMOVE_HOOK_ID(g_iCGamePlayerEquipUseId); SH_REMOVE_HOOK_ID(g_iCGamePlayerEquipPrecacheId); SH_REMOVE_HOOK_ID(g_iCTriggerGravityPrecacheId); @@ -1048,17 +1034,6 @@ void CS2Fixes::Hook_CreateWorkshopMapGroup(const char* name, const CUtlStringLis RETURN_META(MRES_IGNORED); } -void CS2Fixes::Hook_GoToIntermission(bool bAbortedMatch) -{ - if (!g_pMapVoteSystem->IsIntermissionAllowed(false) && g_cvarVoteManagerEnable.Get()) - RETURN_META(MRES_SUPERCEDE); - - if (g_cvarVoteManagerEnable.Get()) - g_pVoteManager->OnIntermission(); - - RETURN_META(MRES_IGNORED); -} - CConVar g_cvarDropMapWeapons("cs2f_drop_map_weapons", FCVAR_NONE, "Whether to force drop map-spawned weapons on death", false); bool CS2Fixes::Hook_OnTakeDamage_Alive(CTakeDamageResult* pDamageResult) diff --git a/src/cs2fixes.h b/src/cs2fixes.h index 924b68650..4290cc242 100644 --- a/src/cs2fixes.h +++ b/src/cs2fixes.h @@ -92,7 +92,6 @@ class CS2Fixes : public ISmmPlugin, public IMetamodListener, public ICS2Fixes void Hook_StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession*, const char*); void Hook_ApplyGameSettings(KeyValues* pKV); void Hook_CreateWorkshopMapGroup(const char* name, const CUtlStringList& mapList); - void Hook_GoToIntermission(bool bAbortedMatch); bool Hook_OnTakeDamage_Alive(CTakeDamageResult* pDamageResult); void Hook_PhysicsTouchShuffle(CUtlVector* pList, bool unknown); void Hook_Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity); diff --git a/src/detours.cpp b/src/detours.cpp index 2c574c9e0..3816f68ce 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -50,6 +50,7 @@ #include "playermanager.h" #include "serversideclient.h" #include "tier0/vprof.h" +#include "votemanager.h" #include "zombiereborn.h" #include "tier0/memdbgon.h" @@ -86,6 +87,7 @@ DECLARE_DETOUR(GameSystem_Think_CheckSteamBan, Detour_GameSystem_Think_CheckStea DECLARE_DETOUR(CCSPlayer_ItemServices_CanAcquire, Detour_CCSPlayer_ItemServices_CanAcquire); DECLARE_DETOUR(CS_Script_SetModel, Detour_CS_Script_SetModel); DECLARE_DETOUR(CBaseModelEntity_SetModel, Detour_CBaseModelEntity_SetModel); +DECLARE_DETOUR(CCSGameRules_GoToIntermission, Detour_CCSGameRules_GoToIntermission); CConVar g_cvarBlockMolotovSelfDmg("cs2f_block_molotov_self_dmg", FCVAR_NONE, "Whether to block self-damage from molotovs", false); CConVar g_cvarBlockAllDamage("cs2f_block_all_dmg", FCVAR_NONE, "Whether to block all damage to players", false); @@ -844,11 +846,22 @@ void FASTCALL Detour_CBaseModelEntity_SetModel(CBaseModelEntity* pModel, const c { if (!g_bInScriptSetModel) return CBaseModelEntity_SetModel(pModel, pszModel); - + if (PrepareMapSetModel(pModel)) return CBaseModelEntity_SetModel(pModel, pszModel); } +void FASTCALL Detour_CCSGameRules_GoToIntermission(CCSGameRules* pThis, bool bAbortedMatch) +{ + if (!g_pMapVoteSystem->IsIntermissionAllowed(false) && g_cvarVoteManagerEnable.Get()) + return; + + if (g_cvarVoteManagerEnable.Get()) + g_pVoteManager->OnIntermission(); + + return CCSGameRules_GoToIntermission(pThis, bAbortedMatch); +} + bool InitDetours(CGameConfig* gameConfig) { bool success = true; diff --git a/src/detours.h b/src/detours.h index f694ae1d8..2700e6ef7 100644 --- a/src/detours.h +++ b/src/detours.h @@ -52,6 +52,7 @@ class CTraceFilter; class Vector; class QAngle; class CEconItemView; +class CCSGameRules; struct CTakeDamageResult; // Add callback functions to this map that wish to hook into Detour_CEntityIOOutput_FireOutputInternal @@ -114,4 +115,5 @@ void FASTCALL Detour_CBaseFilter_InputTestActivator(CBaseEntity* pThis, InputDat void FASTCALL Detour_GameSystem_Think_CheckSteamBan(); AcquireResult FASTCALL Detour_CCSPlayer_ItemServices_CanAcquire(CCSPlayer_ItemServices* pItemServices, CEconItemView* pEconItem, AcquireMethod iAcquireMethod, uint64_t unk4); void FASTCALL Detour_CS_Script_SetModel(uint64_t unk1); -void FASTCALL Detour_CBaseModelEntity_SetModel(CBaseModelEntity* pModel, const char* pszModel); \ No newline at end of file +void FASTCALL Detour_CBaseModelEntity_SetModel(CBaseModelEntity* pModel, const char* pszModel); +void FASTCALL Detour_CCSGameRules_GoToIntermission(CCSGameRules* pThis, bool bAbortedMatch); \ No newline at end of file From 57799d9321dd3779a155983d80b55ce2d2f9c6c7 Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 30 Apr 2026 23:33:50 -0400 Subject: [PATCH 27/32] Make SetModel blocker a map migration as well So servers don't need to do manual map config setup The dedicated cvar may still be useful in other scenarios, however --- cfg/cs2fixes/cs2fixes.cfg | 3 ++- src/detours.cpp | 3 ++- src/mapmigrations.cpp | 7 +++++++ src/mapmigrations.h | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 24f28e97a..b3819b0e4 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -169,4 +169,5 @@ cs2f_disable_hud_outside_round 0 // Whether to disable hud messages that would cs2f_hud_duration_leeway 2 // Extra seconds duration to leave hud messages visible (without priority), reduces transition flashes between different priority messages // Map migrations -cs2f_mapmigrations_20260121 2 // Current mode for 2026-01-21 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-01-21 & disabled if updated after] \ No newline at end of file +cs2f_mapmigrations_20260121 2 // Current mode for 2026-01-21 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-01-21 & disabled if updated after] +cs2f_mapmigrations_20260420 2 // Current mode for 2026-04-20 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-04-20 & disabled if updated after] \ No newline at end of file diff --git a/src/detours.cpp b/src/detours.cpp index 3816f68ce..5af6735d9 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -45,6 +45,7 @@ #include "igameevents.h" #include "irecipientfilter.h" #include "map_votes.h" +#include "mapmigrations.h" #include "module.h" #include "networksystem/inetworkserializer.h" #include "playermanager.h" @@ -416,7 +417,7 @@ bool PrepareMapSetModel(CBaseModelEntity* pModel) if (!pModel->IsPawn()) return true; - if (g_cvarDisableSetModel.Get()) + if (g_cvarDisableSetModel.Get() || g_pMapMigrations->Migrations20260420Enabled()) return false; // Player color may have been changed by zclass/server customization, so reset it first diff --git a/src/mapmigrations.cpp b/src/mapmigrations.cpp index 2ebc5717d..baa795f13 100644 --- a/src/mapmigrations.cpp +++ b/src/mapmigrations.cpp @@ -26,8 +26,10 @@ CMapMigrations* g_pMapMigrations = nullptr; const time_t g_time20260121 = 1769036239; +const time_t g_time20260420 = 1776725888; CConVar g_cvarMapMigrations20260121("cs2f_mapmigrations_20260121", FCVAR_NONE, "Current mode for 2026-01-21 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-01-21 & disabled if updated after]", 2); +CConVar g_cvarMapMigrations20260420("cs2f_mapmigrations_20260420", FCVAR_NONE, "Current mode for 2026-04-20 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-04-20 & disabled if updated after]", 2); void CMapMigrations::ApplyGameSettings(KeyValues* pKV) { @@ -108,6 +110,11 @@ void CMapMigrations::UpdateMapUpdateTime(time_t timeMapUpdated) RunMigrations(pTarget); } +bool CMapMigrations::Migrations20260420Enabled() +{ + return g_cvarMapMigrations20260420.Get() == 1 || (g_cvarMapMigrations20260420.Get() == 2 && m_timeMapUpdated < g_time20260420); +} + std::shared_ptr CMapMigrationWorkshopDetailsQuery::Create(uint64 iWorkshopId) { if (!GetSteamUGC()) diff --git a/src/mapmigrations.h b/src/mapmigrations.h index 4aa357393..77334d2e0 100644 --- a/src/mapmigrations.h +++ b/src/mapmigrations.h @@ -57,6 +57,7 @@ class CMapMigrations void RunMigrations(CBaseEntity* pEntity); void Migrations_20260121(CBaseEntity* pEntity); void UpdateMapUpdateTime(time_t timeMapUpdated); + bool Migrations20260420Enabled(); void AddWorkshopDetailsQuery(std::shared_ptr pQuery) { m_vecWorkshopDetailsQueries.push_back(pQuery); } void RemoveWorkshopDetailsQuery(std::shared_ptr pQuery) { m_vecWorkshopDetailsQueries.erase(std::remove(m_vecWorkshopDetailsQueries.begin(), m_vecWorkshopDetailsQueries.end(), pQuery), m_vecWorkshopDetailsQueries.end()); } From cdbead405235ebfff09715b18e56418bba7cce91 Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 14 May 2026 22:46:51 -0400 Subject: [PATCH 28/32] Update BotNavIgnore patch for 2026-05-14 CS2 update --- gamedata/cs2fixes.jsonc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index ef4c30731..7bbae40bf 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -219,7 +219,7 @@ { "library": "server", "windows": "0F 84 ? ? ? ? 80 B8 ? ? ? ? 00 0F 84 ? ? ? ? 80 3D ? ? ? ? 00 74 15", - "linux": "0F 84 ? ? ? ? 44 0F B6 B0 ? ? ? ? 45 84 F6 0F 84" + "linux": "0F 84 ? ? ? ? 44 0F B6 B8 ? ? ? ? 45 84 FF 0F 84" }, // next to "soundname", in windows it's the last referenced sub while in linux it's right after // this is a vscript binding though so it may be removed in the future? @@ -549,7 +549,7 @@ "BotNavIgnore": { "windows": "E9 2C 00 00 00 90", - "linux": "E9 25 00 00 00 90" + "linux": "E9 22 00 00 00 90" }, // Make func_physbox pass itself as the caller in OnPlayerUse // pCaller = inputdata->pCaller -> pCaller = this From e57c063cbb6ec6dbdf29a71d3452b0624b6280ed Mon Sep 17 00:00:00 2001 From: Vauff Date: Mon, 18 May 2026 20:56:10 -0400 Subject: [PATCH 29/32] Partial gamedata updates for 2026-05-18 CS2 update --- gamedata/cs2fixes.jsonc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 7bbae40bf..82e60e793 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -39,8 +39,8 @@ "ServerMovementUnlock": { "library": "server", - "windows": "0F 86 B0 ? ? ? 0F 57 C0 0F 2E C2", - "linux": "0F 87 ? ? ? ? F3 0F 10 35 ? ? ? ? F3 0F 11 B5" + "windows": "0F 86 AF ? ? ? 0F 57 C0 0F 2E C2", + "linux": "0F 87 ? ? ? ? F3 0F 10 25 ? ? ? ? F3 0F 11 A5 ? ? ? ? 48 89 DE" }, // String: "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam "CCSPlayerController_SwitchTeam": @@ -165,7 +165,7 @@ { "library": "server", "windows": "40 55 56 41 56 48 83 EC ? 48 8B F1 BA ? ? ? ? 8B 0D ? ? ? ? FF 15 ? ? ? ? 4C 8D 35 ? ? ? ? 84 C0 74 ? 8B 0D ? ? ? ? 4C 8D 0D ? ? ? ? 4C 8D 05 ? ? ? ? 4C 89 74 24 ? BA ? ? ? ? FF 15 ? ? ? ? 48 89 9C 24 ? ? ? ? 48 89 BC 24 ? ? ? ? E8 ? ? ? ? 48 8B D0 48 8D 4C 24 ? 48 8B E8 E8 ? ? ? ? E8 ? ? ? ? 48 85 C0 75 ? 48 8D 15 ? ? ? ? E9 ? ? ? ? 48 8D 94 24 ? ? ? ? 48 8B C8 E8 ? ? ? ? 48 8B 5E ? 48 83 EB ? 48 8B CB E8 ? ? ? ? 83 F8 ? 0F 85 ? ? ? ? 48 8B 0B 48 8B 41 ? 0F B7 40 ? 3D ? ? ? ? 74 ? 05 ? ? ? ? 3D ? ? ? ? 76 ? 33 D2 48 8B CB E8 ? ? ? ? EB ? 48 8B 41 ? 48 8D 0D ? ? ? ? 48 3B C1 0F 85 ? ? ? ? 48 8B 0B 48 8B 41 ? 0F B7 40 ? 3D ? ? ? ? 74 ? 05 ? ? ? ? 3D ? ? ? ? 76 ? BA ? ? ? ? 48 8B CB E8 ? ? ? ? EB ? 48 8B 41 ? 48 85 C0 0F 84 ? ? ? ? 33 DB 83 38 ? 75 ? 8B 48 ? 83 F9 ? 74 ? 4C 8B 05 ? ? ? ? 4D 85 C0 74 ? 83 F9 ? 74 ? 8B C1 25 ? ? ? ? 8B D0 48 C1 E8 ? 4D 8B 0C C0 4D 85 C9 74 ? 81 E2 ? ? ? ? 48 6B C2 ? 49 03 C1 74 ? 39 48 ? 48 0F 45 C3 EB ? 48 8B C3 48 85 C0 74 ? 48 8B 08 EB ? 48 8B CB 4C 8D 0D ? ? ? ? 89 5C 24 ? 4C 8D 05 ? ? ? ? 33 D2 E8 ? ? ? ? 48 8B F8 48 85 C0 75 ? 48 8D 15 ? ? ? ? E9 ? ? ? ? 83 7E ? ? 7D ? 8B 0D ? ? ? ? BA ? ? ? ? FF 15 ? ? ? ? 84 C0 0F 84 ? ? ? ? 8B 0D", - "linux": "55 BE ? ? ? ? 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 83 EC ? 4C 8D 3D ? ? ? ? 41 8B 3F E8 ? ? ? ? 84 C0 0F 85 ? ? ? ? E8 ? ? ? ? 4C 8D 6D ? 4C 89 EF 48 89 C6 49 89 C4 E8 ? ? ? ? E8 ? ? ? ? 48 89 C7 48 85 C0 0F 84 ? ? ? ? E8 ? ? ? ? 49 89 C6 48 8B 43 ? 48 8D 78 ? E8 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 83 38 ? 0F 85 ? ? ? ? 8B 48 ? 83 F9 ? 0F 84 ? ? ? ? 48 8B 35 ? ? ? ? 48 85 F6 0F 84 ? ? ? ? 83 F9 ? 0F 84 ? ? ? ? 0F B7 40 ? 48 89 C2 48 C1 EA ? 83 E2 ? 48 8B 14 D6 48 85 D2 0F 84 ? ? ? ? 25 ? ? ? ? 48 6B C0 ? 48 01 D0 3B 48 ? 0F 85 ? ? ? ? 48 8B 38 48 85 FF 0F 84 ? ? ? ? 48 8D 15" + "linux": "55 BE ? ? ? ? 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 83 EC ? 4C 8D 3D ? ? ? ? 41 8B 3F E8 ? ? ? ? 84 C0 0F 85 ? ? ? ? E8 ? ? ? ? 4C 8D 6D ? 4C 89 EF 48 89 C6 49 89 C4 E8 ? ? ? ? E8 ? ? ? ? 48 89 C7 48 85 C0 0F 84 ? ? ? ? E8 ? ? ? ? 49 89 C6 48 8B 43 ? 48 8D 78 ? E8 ? ? ? ? 48 85 C0 0F 84 ? ? ? ? 83 38 ? 0F 85 ? ? ? ? 8B 48 ? 83 F9 ? 0F 84 ? ? ? ? 48 8B 35 ? ? ? ? 48 85 F6 0F 84 ? ? ? ? 83 F9 ? 0F 84 ? ? ? ? 0F B7 40 ? 48 89 C2 48 C1 EA ? 83 E2 ? 48 8B 14 D6 48 85 D2 0F 84 ? ? ? ? 25 ? ? ? ? 48 6B C0 ? 48 01 D0 3B 48 ? 0F 85 ? ? ? ? 48 8B 38 48 85 FF 0F 84 ? ? ? ? 48 8D 15 ? ? ? ? 31 C9 48 8D 35 ? ? ? ? E8 ? ? ? ? 48 85 C0 74 ? 8B 7B ? 85 FF 0F 8E ? ? ? ? 48 8B 73 ? 48 8D 5D" }, // Called by CS_Script_SetModel // This has two identical functions, but because we're detouring for cs_script, we must go beyond function boundaries for a unique signature @@ -537,7 +537,7 @@ { "ServerMovementUnlock": { - "windows": "E9 B1 00 00 00 90", + "windows": "E9 B0 00 00 00 90", "linux": "90 90 90 90 90 90" }, "FixWaterFloorJump": From 92d562b0c63287627d4d6eb77866585850ceec17 Mon Sep 17 00:00:00 2001 From: Vauff Date: Mon, 18 May 2026 21:25:17 -0400 Subject: [PATCH 30/32] Remove CPhysBox_Use patch Seemingly implemented by Valve in the 2026-05-18 CS2 update, it also turns out our EntWatch implementation didn't rely on this --- gamedata/cs2fixes.jsonc | 17 ----------------- src/patches.cpp | 1 - 2 files changed, 18 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 82e60e793..014e536a8 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -258,14 +258,6 @@ "windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 41 0F B6 F0", "linux": "55 48 89 E5 41 57 49 89 FF 41 56 41 55 41 54 53 89 D3 48 81 EC ? ? ? ? 40 38 B7" }, - // Use CBaseEntity::Use offset - // This signature points directly to the instruction to patch - "CPhysBox_Use": - { - "library": "server", - "windows": "4C 8B 43 ? 48 8D 8F ? ? ? ? 48 8B 13 E8 ? ? ? ? 48 8B 5C 24 ? 48 83 C4 ? 5F C3 CC CC CC CC 48 89 5C 24", - "linux": "49 8B 54 24 ? 45 31 C9 45 31 C0 C7 45 ? ? ? ? ? 49 8B 34 24 48 8D 4D ? 66 0F EF C0 48 C7 45 ? ? ? ? ? 48 8D BB ? ? ? ? E8 ? ? ? ? F6 45 ? ? 74 ? 48 8B 05 ? ? ? ? 48 8B 75 ? 48 8B 38 48 8B 07 FF 50 ? 48 83 C4" - }, "CTakeDamageInfo": { "library": "server", @@ -551,15 +543,6 @@ "windows": "E9 2C 00 00 00 90", "linux": "E9 22 00 00 00 90" }, - // Make func_physbox pass itself as the caller in OnPlayerUse - // pCaller = inputdata->pCaller -> pCaller = this - // Windows: mov r8, [rbx+8] -> mov r8, rdi - // Linux: mov rdx, [r12+8] -> mov rdx, rbx - "CPhysBox_Use": - { - "windows": "49 89 F8 90", - "linux": "48 89 DA 90 90" - }, // jnz -> jmp "SetSchemaHammerUniqueId": { diff --git a/src/patches.cpp b/src/patches.cpp index 4e02eeaba..86e6cbbd8 100644 --- a/src/patches.cpp +++ b/src/patches.cpp @@ -33,7 +33,6 @@ CMemPatch g_CommonPatches[] = CMemPatch("ServerMovementUnlock", "ServerMovementUnlock"), CMemPatch("BotNavIgnore", "BotNavIgnore"), CMemPatch("CheckJumpButtonWater", "FixWaterFloorJump"), - CMemPatch("CPhysBox_Use", "CPhysBox_Use"), CMemPatch("SetSchemaHammerUniqueId", "SetSchemaHammerUniqueId"), }; From e5dba2edca7fe3536da0f1dac955091f61a5adf5 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 19 May 2026 12:54:15 -0400 Subject: [PATCH 31/32] Rename hook callback for clarity --- src/cs2fixes.cpp | 4 ++-- src/cs2fixes.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 671ee996f..cac649b1b 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -283,7 +283,7 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool bRequiredInitLoaded = false; } SH_MANUALHOOK_RECONFIGURE(Teleport, offset, 0, 0); - g_iTeleportId = SH_ADD_MANUALDVPHOOK(Teleport, pCCSPlayerPawnVTable, SH_MEMBER(this, &CS2Fixes::Hook_Teleport), false); + g_iTeleportId = SH_ADD_MANUALDVPHOOK(Teleport, pCCSPlayerPawnVTable, SH_MEMBER(this, &CS2Fixes::Hook_CCSPlayerPawn_Teleport), false); const auto pCCSPlayer_MovementServicesVTable = modules::server->FindVirtualTable("CCSPlayer_MovementServices"); offset = g_GameConfig->GetOffset("CCSPlayer_MovementServices::CheckMovingGround"); @@ -1191,7 +1191,7 @@ void CS2Fixes::Hook_SpawnPost(int nCount, const EntitySpawnInfo_t* pInfo) g_pMapMigrations->OnEntitySpawned(pInfo[i].m_pEntity->m_pInstance, pInfo[i].m_pKeyValues); } -void CS2Fixes::Hook_Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity) +void CS2Fixes::Hook_CCSPlayerPawn_Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity) { if (!pAngles) RETURN_META(MRES_IGNORED); diff --git a/src/cs2fixes.h b/src/cs2fixes.h index 4290cc242..18b6eb2b3 100644 --- a/src/cs2fixes.h +++ b/src/cs2fixes.h @@ -94,7 +94,7 @@ class CS2Fixes : public ISmmPlugin, public IMetamodListener, public ICS2Fixes void Hook_CreateWorkshopMapGroup(const char* name, const CUtlStringList& mapList); bool Hook_OnTakeDamage_Alive(CTakeDamageResult* pDamageResult); void Hook_PhysicsTouchShuffle(CUtlVector* pList, bool unknown); - void Hook_Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity); + void Hook_CCSPlayerPawn_Teleport(const Vector* pPosition, const QAngle* pAngles, const Vector* pVelocity); #ifdef PLATFORM_WINDOWS Vector* Hook_GetEyePosition(Vector*); QAngle* Hook_GetEyeAngles(QAngle*); From 0f001e4ce1da0d23bc0e882c7d3b21003b230f81 Mon Sep 17 00:00:00 2001 From: Vauff Date: Tue, 19 May 2026 13:54:33 -0400 Subject: [PATCH 32/32] Add a map migration for parented weapon entity heights --- src/detours.cpp | 2 ++ src/mapmigrations.cpp | 48 +++++++++++++++++++++++++++++++++++++++---- src/mapmigrations.h | 6 +++++- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/detours.cpp b/src/detours.cpp index 5af6735d9..683881c72 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -407,6 +407,8 @@ void FASTCALL Detour_CCSPlayer_WeaponServices_EquipWeapon(CCSPlayer_WeaponServic if (g_cvarEnableEntWatch.Get()) EW_Detour_CCSPlayer_WeaponServices_EquipWeapon(pWeaponServices, pPlayerWeapon); + g_pMapMigrations->OnEquipWeapon(pPlayerWeapon); + return CCSPlayer_WeaponServices_EquipWeapon(pWeaponServices, pPlayerWeapon); } diff --git a/src/mapmigrations.cpp b/src/mapmigrations.cpp index baa795f13..2a9340505 100644 --- a/src/mapmigrations.cpp +++ b/src/mapmigrations.cpp @@ -22,6 +22,7 @@ #include "entity.h" #include "entity/cbasemodelentity.h" #include "utils.h" +#include "vprof.h" CMapMigrations* g_pMapMigrations = nullptr; @@ -45,6 +46,7 @@ void CMapMigrations::ApplyGameSettings(KeyValues* pKV) void CMapMigrations::OnRoundPrestart() { m_vecModelEntitiesUsingRendermodeEnum.clear(); + m_vecEquippedWeapons.clear(); } void CMapMigrations::OnEntitySpawned(CEntityInstance* pEntity, const CEntityKeyValues* pKeyValues) @@ -59,6 +61,12 @@ void CMapMigrations::OnEntitySpawned(CEntityInstance* pEntity, const CEntityKeyV RunMigrations(pBaseEntity); } +void CMapMigrations::OnEquipWeapon(CBasePlayerWeapon* pWeapon) +{ + if (Migrations20260420Enabled()) + Migrations_20260420(pWeapon); +} + void CMapMigrations::RunMigrations(CBaseEntity* pEntity) { if (g_cvarMapMigrations20260121.Get() == 1 || (g_cvarMapMigrations20260121.Get() == 2 && m_timeMapUpdated < g_time20260121)) @@ -99,15 +107,36 @@ void CMapMigrations::Migrations_20260121(CBaseEntity* pEntity) } } -void CMapMigrations::UpdateMapUpdateTime(time_t timeMapUpdated) +void CMapMigrations::Migrations_20260420(CBasePlayerWeapon* pWeapon) { - m_timeMapUpdated = timeMapUpdated; + VPROF("CMapMigrations::Migrations_20260420"); + + // We only care about map-spawned weapons + if (!V_strcmp(pWeapon->m_sUniqueHammerID().Get(), "")) + return; + + // And only their first equip + for (int i = 0; i < m_vecEquippedWeapons.size(); i++) + if (m_vecEquippedWeapons[i] == pWeapon->GetHandle()) + return; + m_vecEquippedWeapons.push_back(pWeapon->GetHandle()); CBaseEntity* pTarget = nullptr; - // May be called late, so also check any existing entities first + // Entities parented to weapons being held by players were offset by +40 units following the AG2 update + // Since that doesn't affect in-world weapons, this migration is delayed until weapon equip to prevent breaking strip triggers etc + // Alternatively, we may want to track weapon children ahead of time via OnEntityParentChanged if this ends up becoming a performance concern while ((pTarget = UTIL_FindEntityByClassname(pTarget, "*"))) - RunMigrations(pTarget); + { + CGameSceneNode* pParentSceneNode = pTarget->m_CBodyComponent()->m_pSceneNode()->m_pParent(); + + if (pParentSceneNode && pParentSceneNode->m_pOwner() == pWeapon) + { + Vector newOrigin = pTarget->GetAbsOrigin(); + newOrigin.z -= 40.0f; + pTarget->Teleport(&newOrigin, nullptr, nullptr); + } + } } bool CMapMigrations::Migrations20260420Enabled() @@ -115,6 +144,17 @@ bool CMapMigrations::Migrations20260420Enabled() return g_cvarMapMigrations20260420.Get() == 1 || (g_cvarMapMigrations20260420.Get() == 2 && m_timeMapUpdated < g_time20260420); } +void CMapMigrations::UpdateMapUpdateTime(time_t timeMapUpdated) +{ + m_timeMapUpdated = timeMapUpdated; + + CBaseEntity* pTarget = nullptr; + + // May be called late, so also check any existing entities first + while ((pTarget = UTIL_FindEntityByClassname(pTarget, "*"))) + RunMigrations(pTarget); +} + std::shared_ptr CMapMigrationWorkshopDetailsQuery::Create(uint64 iWorkshopId) { if (!GetSteamUGC()) diff --git a/src/mapmigrations.h b/src/mapmigrations.h index 77334d2e0..18ba34044 100644 --- a/src/mapmigrations.h +++ b/src/mapmigrations.h @@ -21,6 +21,7 @@ #include "KeyValues.h" #include "convar.h" +#include "cs2_sdk/entity/ccsweaponbase.h" #include "ehandle.h" #include "entitysystem.h" #include "steam/isteamugc.h" @@ -54,10 +55,12 @@ class CMapMigrations void ApplyGameSettings(KeyValues* pKV); void OnRoundPrestart(); void OnEntitySpawned(CEntityInstance* pEntity, const CEntityKeyValues* pKeyValues); + void OnEquipWeapon(CBasePlayerWeapon* pWeapon); void RunMigrations(CBaseEntity* pEntity); void Migrations_20260121(CBaseEntity* pEntity); - void UpdateMapUpdateTime(time_t timeMapUpdated); + void Migrations_20260420(CBasePlayerWeapon* pWeapon); bool Migrations20260420Enabled(); + void UpdateMapUpdateTime(time_t timeMapUpdated); void AddWorkshopDetailsQuery(std::shared_ptr pQuery) { m_vecWorkshopDetailsQueries.push_back(pQuery); } void RemoveWorkshopDetailsQuery(std::shared_ptr pQuery) { m_vecWorkshopDetailsQueries.erase(std::remove(m_vecWorkshopDetailsQueries.begin(), m_vecWorkshopDetailsQueries.end(), pQuery), m_vecWorkshopDetailsQueries.end()); } @@ -65,6 +68,7 @@ class CMapMigrations time_t m_timeMapUpdated = std::numeric_limits::max(); std::vector> m_vecWorkshopDetailsQueries; std::vector> m_vecModelEntitiesUsingRendermodeEnum; + std::vector> m_vecEquippedWeapons; }; extern CMapMigrations* g_pMapMigrations; \ No newline at end of file