From b8d286640cbb9f8086078c6819ab4633c541058d Mon Sep 17 00:00:00 2001
From: Maxime Leroy <19607336+maxime1907@users.noreply.github.com>
Date: Mon, 16 Oct 2023 21:45:23 +0200
Subject: [PATCH] feat: gamedata support (#36)
---
.gitignore | 3 +-
AMBuilder | 3 +-
CS2Fixes.vcxproj | 1 +
CS2Fixes.vcxproj.filters | 3 +
PackageScript | 2 +
gamedata/cs2fixes.games.txt | 246 +++++++++++++++++
src/addresses.cpp | 19 +-
src/addresses.h | 129 +--------
src/adminsystem.cpp | 2 +-
src/cdetour.h | 36 +--
src/common.h | 3 -
src/cs2_sdk/entity/cbaseentity.h | 7 +-
.../interfaces/cgameresourceserviceserver.h | 9 +-
src/cs2fixes.cpp | 64 ++++-
src/detours.cpp | 71 +++--
src/detours.h | 3 +-
src/events.cpp | 6 +
src/gameconfig.cpp | 260 ++++++++++++++++++
src/gameconfig.h | 40 +++
src/mempatch.cpp | 21 +-
src/mempatch.h | 15 +-
src/patches.cpp | 30 +-
src/patches.h | 6 +
23 files changed, 748 insertions(+), 231 deletions(-)
create mode 100644 gamedata/cs2fixes.games.txt
create mode 100644 src/gameconfig.cpp
create mode 100644 src/gameconfig.h
create mode 100644 src/patches.h
diff --git a/.gitignore b/.gitignore
index 439e7032..7c4dc0ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,5 @@ bld/
[Bb]in/
[Oo]bj/
.vs/
-*.vcxproj.user
\ No newline at end of file
+*.vcxproj.user
+.vscode
diff --git a/AMBuilder b/AMBuilder
index 952f0e6d..c1df8d06 100644
--- a/AMBuilder
+++ b/AMBuilder
@@ -60,7 +60,8 @@ for sdk_name in MMSPlugin.sdks:
'src/cs2_sdk/interfaces/cs2_interfaces.cpp',
'src/cs2_sdk/interfaces/centitysystem.cpp',
'src/ctimer.cpp',
- 'src/playermanager.cpp'
+ 'src/playermanager.cpp',
+ 'src/gameconfig.cpp',
]
if sdk_name in ['dota', 'cs2']:
diff --git a/CS2Fixes.vcxproj b/CS2Fixes.vcxproj
index dda824f4..d04ccd57 100644
--- a/CS2Fixes.vcxproj
+++ b/CS2Fixes.vcxproj
@@ -177,6 +177,7 @@
+
diff --git a/CS2Fixes.vcxproj.filters b/CS2Fixes.vcxproj.filters
index 7416f92e..7e2e08bb 100644
--- a/CS2Fixes.vcxproj.filters
+++ b/CS2Fixes.vcxproj.filters
@@ -89,6 +89,9 @@
Source Files
+
+ Source Files
+
diff --git a/PackageScript b/PackageScript
index 5d4f554b..6bfe5d90 100644
--- a/PackageScript
+++ b/PackageScript
@@ -51,4 +51,6 @@ with open(os.path.join(builder.buildPath, 'pdblog.txt'), 'wt') as fp:
# Add CS2Fixes-specific files
builder.AddFolder(os.path.join('addons', MMSPlugin.plugin_name, 'data'))
configs_folder = builder.AddFolder(os.path.join('addons', MMSPlugin.plugin_name, 'configs'))
+gamedata_folder = builder.AddFolder(os.path.join('addons', MMSPlugin.plugin_name, 'gamedata'))
builder.AddCopy(os.path.join(builder.sourcePath, 'configs', 'admins.cfg'), configs_folder)
+builder.AddCopy(os.path.join('gamedata', 'cs2fixes.games.txt'), gamedata_folder)
diff --git a/gamedata/cs2fixes.games.txt b/gamedata/cs2fixes.games.txt
new file mode 100644
index 00000000..b94227b6
--- /dev/null
+++ b/gamedata/cs2fixes.games.txt
@@ -0,0 +1,246 @@
+"Games"
+{
+ "csgo"
+ {
+ "Signatures"
+ {
+ // Logging
+ "Msg"
+ {
+ "library" "tier0"
+ "windows" "@Msg"
+ "linux" "@Msg"
+ }
+ "ConDMsg"
+ {
+ "library" "tier0"
+ "windows" "@ConDMsg"
+ "linux" "@ConDMsg"
+ }
+ "DevMsg"
+ {
+ "library" "tier0"
+ "windows" "@DevMsg"
+ "linux" "@DevMsg"
+ }
+ "Warning"
+ {
+ "library" "tier0"
+ "windows" "@Warning"
+ "linux" "@Warning"
+ }
+ "DevWarning"
+ {
+ "library" "tier0"
+ "windows" "@DevWarning"
+ "linux" "@DevWarning"
+ }
+ "LoggingSystem_Log"
+ {
+ "library" "tier0"
+ "windows" "@LoggingSystem_Log"
+ "linux" "@LoggingSystem_Log"
+ }
+ "LoggingSystem_LogDirect"
+ {
+ "library" "tier0"
+ "windows" "@LoggingSystem_LogDirect"
+ "linux" "@LoggingSystem_LogDirect"
+ }
+ "LoggingSystem_LogAssert"
+ {
+ "library" "tier0"
+ "windows" "@LoggingSystem_LogAssert"
+ "linux" "@LoggingSystem_LogAssert"
+ }
+
+ // String: "\"Console<0>\" say \"%s\"\n"
+ "Host_Say"
+ {
+ "library" "server"
+ "windows" "\x44\x89\x4C\x24\x2A\x44\x88\x44\x24\x2A\x55\x53\x56\x57\x41\x54\x41\x55"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xFF\x41\x56\x41\x55\x41\x54\x4D\x89\xC4"
+ }
+ // Called from Host_Say
+ "UTIL_SayTextFilter"
+ {
+ "library" "server"
+ "windows" "\x48\x89\x5C\x24\x2A\x55\x56\x57\x48\x8D\x6C\x24\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x49\x8B\xD8"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xD7\x31\xD2\x41\x56\x4C\x8D\x75\x98"
+ }
+ // Called from Host_Say
+ "UTIL_SayText2Filter"
+ {
+ "library" "server"
+ "windows" "\x48\x89\x5C\x24\x2A\x55\x56\x57\x48\x8D\x6C\x24\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x41\x0F\xB6\xF8"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x4C\x8D\xBD\x2A\x2A\x2A\x2A\x41\x56\x4D\x89\xC6\x41\x55\x4D\x89\xCD"
+ }
+ // String: ""
+ "UTIL_ClientPrintAll"
+ {
+ "library" "server"
+ "windows" "\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x81\xEC\x70\x01\x2A\x2A\x8B\xE9"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xD7\x41\x56\x49\x89\xF6\x41\x55\x41\x89\xFD"
+ }
+ // String: "Console command too long"
+ "ClientPrint"
+ {
+ "library" "server"
+ "windows" "\x48\x85\xC9\x0F\x84\x2A\x2A\x2A\x2A\x48\x8B\xC4\x48\x89\x58\x18"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xCF\x41\x56\x49\x89\xD6\x41\x55\x41\x89\xF5\x41\x54\x4C\x8D\xA5\xA0\xFE\xFF\xFF"
+ }
+ "NetworkStateChanged"
+ {
+ "library" "server"
+ "windows" "\x4C\x8B\xC9\x48\x8B\x09\x48\x85\xC9\x74\x2A\x48\x8B\x41\x10"
+ "linux" "\x4C\x8B\x07\x4D\x85\xC0\x74\x2A\x49\x8B\x40\x10"
+ }
+ "StateChanged"
+ {
+ "library" "server"
+ "windows" "\x48\x89\x54\x24\x10\x55\x53\x57\x41\x55"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x89\xD3"
+ }
+ "VoiceShouldHear"
+ {
+ "library" "engine"
+ "windows" "\x48\x89\x5C\x24\x10\x44\x88\x4C\x24\x20\x44\x88\x44\x24\x18"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x41\x89\xD7\x41\x56\x49\x89\xF6\x41\x55\x41\x54\x49\x89\xFC\x53\x48\x83\xEC\x28"
+ }
+ "IsHearingClient"
+ {
+ "library" "engine"
+ "windows" "\x40\x53\x48\x83\xEC\x20\x48\x8B\xD9\x3B\x91\xB8"
+ "linux" "\x55\x48\x89\xE5\x41\x55\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x08\x3B\xB7\xC8"
+ }
+ // String: "Playing sound on non-networked entity %s"
+ "CSoundEmitterSystem_EmitSound"
+ {
+ "library" "server"
+ "windows" "\x48\x8B\xC4\x4C\x89\x40\x18\x55\x57"
+ "linux" "\x48\xB8\x2A\x2A\x2A\x2A\xFF\xFF\xFF\xFF\x55\x48\x89\xE5\x41\x57\x41\x89\xF7"
+ }
+ // String: "hammerUniqueId"
+ "CBaseEntity_Spawn"
+ {
+ "library" "server"
+ "windows" "\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x83\xEC\x30\x48\x8B\xF2"
+ "linux" "\x55\x48\x89\xE5\x41\x56\x41\x55\x41\x54\x49\x89\xF4\x53\x48\x89\xFB\x48\x83\xEC\x10\xE8\x2A\x2A\x2A\x2A"
+ }
+ // Is the 4th function in the CCSWeaponBase vtable
+ "CCSWeaponBase_Spawn"
+ {
+ "library" "server"
+ "windows" "\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x18\x48\x89\x74\x24\x20\x57\x48\x83\xEC\x30\x48\x8B\xDA\x48\x8B\xE9\xE8\x2A\x2A\x2A\x2A"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x4C\x8D\x75\xC0\x41\x55\x49\x89\xFD\x41\x54\x49\x89\xF4"
+ }
+ // idk a good way to find this again, i just brute forced the vtable. offset is 133 on CTriggerPush
+ "TriggerPush_Touch"
+ {
+ "library" "server"
+ "windows" "\x48\x89\x5C\x24\x10\x48\x89\x7C\x24\x18\x55\x48\x8D\xAC\x24\x60\xE0\xFF\xFF"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x49\x89\xFC\x53\x48\x81\xEC\x28\x20\x2A\x2A\xE8"
+ }
+ // 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\x10\x48\x89\x6C\x24\x18\x48\x89\x7C\x24\x20\x41\x56\x48\x83\xEC\x20\x0F\xB6\x81\xC0\x02\x2A\x2A\x48"
+ "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x49\x89\xFC\x53\x48\x83\xEC\x08\x0F\xB6\x87\xA8\x05\x2A\x2A\x83"
+ }
+ // Check vauff's pin in #scripting
+ "ServerMovementUnlock"
+ {
+ "library" "server"
+ "windows" "\x76\x2A\xF2\x0F\x10\x57\x2A\xF3\x0F\x10\x2A\x2A\x0F\x28\xCA\xF3\x0F\x59\xC0"
+ "linux" "\x0F\x87\x2A\x2A\x2A\x2A\x49\x8B\x7C\x24\x2A\xE8\x2A\x2A\x2A\x2A\x66\x0F\xEF\xED\x66\x0F\xD6\x85\x2A\x2A\x2A\x2A"
+ }
+ // Check vauff's pin in #scripting
+ "ClientMovementUnlock"
+ {
+ "library" "client"
+ "windows" "\x76\x2A\xF2\x0F\x10\x57\x2A\xF3\x0F\x10\x2A\x2A\x0F\x28\xCA\xF3\x0F\x59\xC0"
+ "linux" "\x0F\x87\x2A\x2A\x2A\x2A\x49\x8B\x7C\x24\x2A\xE8\x2A\x2A\x2A\x2A\x66\x0F\xEF\xED\x66\x0F\xD6\x85\x2A\x2A\x2A\x2A"
+ }
+ // Check tilgep's pin in #scripting
+ "VScriptEnable"
+ {
+ "library" "vscript"
+ "windows" "\xBE\x01\x2A\x2A\x2A\x2B\xD6\x74\x2A\x3B\xD6"
+ "linux" "\x83\xFE\x01\x0F\x84\x2A\x2A\x2A\x2A\x83"
+ }
+ // String: "Noise removal", there should be 3 customermachine checks
+ "HammerNoCustomerMachine"
+ {
+ "library" "hammer"
+ "windows" "\xFF\x15\x2A\x2A\x2A\x2A\x84\xC0\x0F\x85\x2A\x2A\x2A\x2A\xB9"
+ "linux" ""
+ }
+ // 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\x48\x8B\x4B\x30"
+ "linux" "\xC8\x42\x66\x0F\xEF\xE4\x41\x0F\x2F\x65"
+ }
+ // String: "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam
+ "CCSPlayerController_SwitchTeam"
+ {
+ "library" "server"
+ "windows" "\x40\x56\x57\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8B\xF9\x8B\xF2\x8B\xCA"
+ "linux" "\x55\x48\x89\xE5\x41\x55\x49\x89\xFD\x89\xF7"
+ }
+ }
+ "Offsets"
+ {
+ "GameEntitySystem"
+ {
+ "windows" "88"
+ "linux" "80"
+ }
+ "Teleport"
+ {
+ "windows" "148"
+ "linux" "147"
+ }
+ "CollisionRulesChanged"
+ {
+ "windows" "173"
+ "linux" "172"
+ }
+ }
+ "Patches"
+ {
+ // Server
+ "ServerMovementUnlock"
+ {
+ "windows" "\xEB"
+ "linux" "\x90\x90\x90\x90\x90\x90"
+ }
+ "VScriptEnable"
+ {
+ "windows" "\xBE\x02"
+ "linux" "\x83\xFE\x02"
+ }
+ "FixWaterFloorJump"
+ {
+ "windows" "\x11\x43"
+ "linux" "\x11\x43"
+ }
+
+ // Client
+ "ClientMovementUnlock"
+ {
+ "windows" "\xEB"
+ "linux" "\x90\x90\x90\x90\x90\x90"
+ }
+
+ // Hammer
+ "HammerNoCustomerMachine"
+ {
+ "windows" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
+ "linux" ""
+ }
+ }
+ }
+}
diff --git a/src/addresses.cpp b/src/addresses.cpp
index e275691f..b03f5be8 100644
--- a/src/addresses.cpp
+++ b/src/addresses.cpp
@@ -24,9 +24,10 @@
#include "tier0/memdbgon.h"
-#define RESOLVE_SIG(module, sig, variable) variable = (decltype(variable))module->FindSignature((uint8*)sig)
+#define RESOLVE_SIG(gameConfig, name, variable) \
+ variable = (decltype(variable))gameConfig->ResolveSignature(name)
-void addresses::Initialize()
+void addresses::Initialize(CGameConfig *g_GameConfig)
{
modules::engine = new CModule(ROOTBIN, "engine2");
modules::tier0 = new CModule(ROOTBIN, "tier0");
@@ -44,10 +45,10 @@ void addresses::Initialize()
modules::hammer = new CModule(ROOTBIN, "tools/hammer");
#endif
- RESOLVE_SIG(modules::server, sigs::NetworkStateChanged, addresses::NetworkStateChanged);
- RESOLVE_SIG(modules::server, sigs::StateChanged, addresses::StateChanged);
- RESOLVE_SIG(modules::server, sigs::UTIL_ClientPrintAll, addresses::UTIL_ClientPrintAll);
- RESOLVE_SIG(modules::server, sigs::ClientPrint, addresses::ClientPrint);
- RESOLVE_SIG(modules::server, sigs::SetGroundEntity, addresses::SetGroundEntity);
- RESOLVE_SIG(modules::server, sigs::CCSPlayerController_SwitchTeam, addresses::CCSPlayerController_SwitchTeam);
-}
\ No newline at end of file
+ RESOLVE_SIG(g_GameConfig, "NetworkStateChanged", addresses::NetworkStateChanged);
+ RESOLVE_SIG(g_GameConfig, "StateChanged", addresses::StateChanged);
+ RESOLVE_SIG(g_GameConfig, "UTIL_ClientPrintAll", addresses::UTIL_ClientPrintAll);
+ RESOLVE_SIG(g_GameConfig, "ClientPrint", addresses::ClientPrint);
+ RESOLVE_SIG(g_GameConfig, "SetGroundEntity", addresses::SetGroundEntity);
+ RESOLVE_SIG(g_GameConfig, "CCSPlayerController_SwitchTeam", addresses::CCSPlayerController_SwitchTeam);
+}
diff --git a/src/addresses.h b/src/addresses.h
index 7b52d6c9..348dc4f3 100644
--- a/src/addresses.h
+++ b/src/addresses.h
@@ -40,10 +40,11 @@ class CEntityInstance;
class CBasePlayerController;
class CCSPlayerController;
class Z_CBaseEntity;
+class CGameConfig;
namespace addresses
{
- void Initialize();
+ void Initialize(CGameConfig *g_GameConfig);
inline void(FASTCALL *NetworkStateChanged)(int64 chainEntity, int64 offset, int64 a3);
inline void(FASTCALL *StateChanged)(void *networkTransmitComponent, CEntityInstance *ent, int64 offset, int16 a4, int16 a5);
@@ -52,129 +53,3 @@ namespace addresses
inline void(FASTCALL *SetGroundEntity)(Z_CBaseEntity *ent, Z_CBaseEntity *ground);
inline void(FASTCALL *CCSPlayerController_SwitchTeam)(CCSPlayerController *pController, uint32 team);
}
-
-namespace offsets
-{
-#ifdef _WIN32
- inline constexpr int GameEntitySystem = 0x58;
- inline constexpr int Teleport = 148;
- // PhysDisableEntityCollisions called on entities in two different scene
- inline constexpr int CollisionRulesChanged = 173;
-#else
- inline constexpr int GameEntitySystem = 0x50;
- inline constexpr int Teleport = 147;
- // PhysDisableEntityCollisions called on entities in two different scene
- inline constexpr int CollisionRulesChanged = 172;
-#endif
-}
-
-namespace sigs
-{
-#ifdef _WIN32
-// Functions
- // look for string "\"Console<0>\" say \"%s\"\n"
- inline const byte *Host_Say = (byte *)"\x44\x89\x4C\x24\x2A\x44\x88\x44\x24\x2A\x55\x53\x56\x57\x41\x54\x41\x55";
-
- // both of these are called from Host_Say
- inline const byte *UTIL_SayTextFilter = (byte *)"\x48\x89\x5C\x24\x2A\x55\x56\x57\x48\x8D\x6C\x24\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x49\x8B\xD8";
- inline const byte *UTIL_SayText2Filter = (byte *)"\x48\x89\x5C\x24\x2A\x55\x56\x57\x48\x8D\x6C\x24\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x41\x0F\xB6\xF8";
-
- // "" is given as a parameter to this
- inline const byte *UTIL_ClientPrintAll = (byte *)"\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x81\xEC\x70\x01\x2A\x2A\x8B\xE9";
-
- // "Console command too long" is given as a parameter to this
- inline const byte *ClientPrint = (byte *)"\x48\x85\xC9\x0F\x84\x2A\x2A\x2A\x2A\x48\x8B\xC4\x48\x89\x58\x18";
-
- inline const byte *NetworkStateChanged = (byte *)"\x4C\x8B\xC9\x48\x8B\x09\x48\x85\xC9\x74\x2A\x48\x8B\x41\x10";
- inline const byte *StateChanged = (byte *)"\x48\x89\x54\x24\x10\x55\x53\x57\x41\x55";
-
- inline const byte *VoiceShouldHear = (byte *)"\x48\x89\x5C\x24\x10\x44\x88\x4C\x24\x20\x44\x88\x44\x24\x18";
- inline const byte *IsHearingClient = (byte *)"\x40\x53\x48\x83\xEC\x20\x48\x8B\xD9\x3B\x91\xB8";
-
- // Find "Playing sound on non-networked entity %s"
- inline const byte *CSoundEmitterSystem_EmitSound = (byte *)"\x48\x8B\xC4\x4C\x89\x40\x18\x55\x57";
-
- // Has string "hammerUniqueId"
- inline const byte *CBaseEntity_Spawn = (byte *)"\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x83\xEC\x30\x48\x8B\xF2";
-
- // Is the 4th function in the CCSWeaponBase vtable
- inline const byte *CCSWeaponBase_Spawn = (byte *)"\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x18\x48\x89\x74\x24\x20\x57\x48\x83\xEC\x30\x48\x8B\xDA\x48\x8B\xE9\xE8\x2A\x2A\x2A\x2A";
-
- // idk a good way to find this again, i just brute forced the vtable. offset is 133 on CTriggerPush
- inline const byte *TriggerPush_Touch = (byte *)"\x48\x89\x5C\x24\x10\x48\x89\x7C\x24\x18\x55\x48\x8D\xAC\x24\x60\xE0\xFF\xFF";
-
- // this is called in CTriggerPush::Touch, using IDA pseudocode look in an `if ( ( v & 0x80 ) != 0 )` and then `if ( v > 0.0 ) SetGroundEntity()`
- inline const byte *SetGroundEntity = (byte *)"\x48\x89\x5C\x24\x10\x48\x89\x6C\x24\x18\x48\x89\x7C\x24\x20\x41\x56\x48\x83\xEC\x20\x0F\xB6\x81\xC0\x02\x2A\x2A\x48";
-
- // literally just look for "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam
- inline const byte *CCSPlayerController_SwitchTeam = (byte *)"\x40\x56\x57\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8B\xF9\x8B\xF2\x8B\xCA";
-
-// Patches
- // Check vauff's pin in #scripting
- inline const byte *MovementUnlock = (byte *)"\x76\x2A\xF2\x0F\x10\x57\x2A\xF3\x0F\x10\x2A\x2A\x0F\x28\xCA\xF3\x0F\x59\xC0";
- inline const byte *Patch_MovementUnlock = (byte *)"\xEB";
-
- // Check tilgep's pin in #scripting
- inline const byte *VScriptEnable = (byte *)"\xBE\x01\x2A\x2A\x2A\x2B\xD6\x74\x2A\x3B\xD6";
- inline const byte *Patch_VScriptEnable = (byte *)"\xBE\x02";
-
- // Find "Noise removal", there should be 3 customermachine checks
- inline const byte *HammerNoCustomerMachine = (byte *)"\xFF\x15\x2A\x2A\x2A\x2A\x84\xC0\x0F\x85\x2A\x2A\x2A\x2A\xB9";
- inline const byte *Patch_HammerNoCustomerMachine = (byte *)"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90";
-
- // Find "player_jump", then find 42C80000h or in pseudocode "*(a2 + 68) = 1120403456;", changing from 100 to 145
- inline const byte* CheckJumpButtonWater = (byte*)"\xC8\x42\xEB\x2A\x48\x8B\x4B\x30";
- inline const byte* Patch_CheckJumpButton = (byte*)"\x11\x43";
-#else
-// Functions
- // look for string "\"Console<0>\" say \"%s\"\n"
- inline const byte *Host_Say = (byte *)"\x55\x48\x89\xE5\x41\x57\x49\x89\xFF\x41\x56\x41\x55\x41\x54\x4D\x89\xC4";
-
- // both of these are called from Host_Say
- inline const byte *UTIL_SayTextFilter = (byte *)"\x55\x48\x89\xE5\x41\x57\x49\x89\xD7\x31\xD2\x41\x56\x4C\x8D\x75\x98";
- inline const byte *UTIL_SayText2Filter = (byte *)"\x55\x48\x89\xE5\x41\x57\x4C\x8D\xBD\x2A\x2A\x2A\x2A\x41\x56\x4D\x89\xC6\x41\x55\x4D\x89\xCD";
-
- // "" is given as a parameter to this
- inline const byte *UTIL_ClientPrintAll = (byte *)"\x55\x48\x89\xE5\x41\x57\x49\x89\xD7\x41\x56\x49\x89\xF6\x41\x55\x41\x89\xFD";
-
- // "Console command too long" is given as a paramterer to this
- inline const byte *ClientPrint = (byte *)"\x55\x48\x89\xE5\x41\x57\x49\x89\xCF\x41\x56\x49\x89\xD6\x41\x55\x41\x89\xF5\x41\x54\x4C\x8D\xA5\xA0\xFE\xFF\xFF";
-
- inline const byte *NetworkStateChanged = (byte *)"\x4C\x8B\x07\x4D\x85\xC0\x74\x2A\x49\x8B\x40\x10";
- inline const byte *StateChanged = (byte *)"\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x89\xD3";
-
- inline const byte *VoiceShouldHear = (byte *)"\x55\x48\x89\xE5\x41\x57\x41\x89\xD7\x41\x56\x49\x89\xF6\x41\x55\x41\x54\x49\x89\xFC\x53\x48\x83\xEC\x28";
- inline const byte *IsHearingClient = (byte *)"\x55\x48\x89\xE5\x41\x55\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x08\x3B\xB7\xC8";
-
- // Find "Playing sound on non-networked entity %s"
- inline const byte *CSoundEmitterSystem_EmitSound = (byte *)"\x48\xB8\x2A\x2A\x2A\x2A\xFF\xFF\xFF\xFF\x55\x48\x89\xE5\x41\x57\x41\x89\xF7";
-
- // Has string "hammerUniqueId"
- inline const byte *CBaseEntity_Spawn = (byte *)"\x55\x48\x89\xE5\x41\x56\x41\x55\x41\x54\x49\x89\xF4\x53\x48\x89\xFB\x48\x83\xEC\x10\xE8\x2A\x2A\x2A\x2A";
-
- // Is the 4th function in the CCSWeaponBase vtable
- inline const byte *CCSWeaponBase_Spawn = (byte *)"\x55\x48\x89\xE5\x41\x57\x41\x56\x4C\x8D\x75\xC0\x41\x55\x49\x89\xFD\x41\x54\x49\x89\xF4";
-
- // idk a good way to find this again, i just brute forced the vtable. offset is 133 on CTriggerPush
- inline const byte *TriggerPush_Touch = (byte *)"\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x49\x89\xFC\x53\x48\x81\xEC\x28\x20\x2A\x2A\xE8";
-
- // this is called in CTriggerPush::Touch, using IDA pseudocode look in an `if ( ( v & 0x80 ) != 0 )` and then `if ( v > 0.0 ) SetGroundEntity()`
- inline const byte *SetGroundEntity = (byte *)"\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x49\x89\xFC\x53\x48\x83\xEC\x08\x0F\xB6\x87\xA8\x05\x2A\x2A\x83";
-
- // literally just look for "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam
- inline const byte *CCSPlayerController_SwitchTeam = (byte *)"\x55\x48\x89\xE5\x41\x55\x49\x89\xFD\x89\xF7";
-
-// Patches
- // Check vauff's pin in #scripting
- inline const byte *MovementUnlock = (byte *)"\x0F\x87\x2A\x2A\x2A\x2A\x49\x8B\x7C\x24\x2A\xE8\x2A\x2A\x2A\x2A\x66\x0F\xEF\xED\x66\x0F\xD6\x85\x2A\x2A\x2A\x2A";
- inline const byte *Patch_MovementUnlock = (byte *)"\x90\x90\x90\x90\x90\x90";
-
- // Check tilgep's pin in #scripting
- inline const byte *VScriptEnable = (byte *)"\x83\xFE\x01\x0F\x84\x2A\x2A\x2A\x2A\x83";
- inline const byte *Patch_VScriptEnable = (byte *)"\x83\xFE\x02";
-
- // Find "player_jump", then find 42C80000h or in pseudocode "*(a2 + 68) = 1120403456;", changing from 100 to 145
- inline const byte* CheckJumpButtonWater = (byte*)"\xC8\x42\x66\x0F\xEF\xE4\x41\x0F\x2F\x65";
- inline const byte* Patch_CheckJumpButton = (byte*)"\x11\x43";
-#endif
-}
\ No newline at end of file
diff --git a/src/adminsystem.cpp b/src/adminsystem.cpp
index 8731eb7b..bdc985fc 100644
--- a/src/adminsystem.cpp
+++ b/src/adminsystem.cpp
@@ -30,7 +30,7 @@
extern IVEngineServer2 *g_pEngineServer2;
extern CEntitySystem *g_pEntitySystem;
-CAdminSystem* g_pAdminSystem;
+CAdminSystem* g_pAdminSystem = nullptr;
CUtlMap g_CommandList(0, 0, DefLessFunc(uint32));
diff --git a/src/cdetour.h b/src/cdetour.h
index bcaa78ca..fa203904 100644
--- a/src/cdetour.h
+++ b/src/cdetour.h
@@ -23,6 +23,8 @@
#include "module.h"
#include "utlvector.h"
#include "plat.h"
+#include "gameconfig.h"
+#include "addresses.h"
class CDetourBase
{
@@ -35,11 +37,14 @@ template
class CDetour : public CDetourBase
{
public:
- CDetour(CModule** pModule, T* pfnDetour, const char* pszName, byte* pSignature = nullptr) :
- m_pModule(pModule), m_pfnDetour(pfnDetour), m_pszName(pszName), m_pSignature(pSignature)
+ CDetour(T* pfnDetour, const char* pszName) :
+ m_pfnDetour(pfnDetour), m_pszName(pszName)
{
m_hook = nullptr;
m_bInstalled = false;
+ m_pSignature = nullptr;
+ m_pSymbol = nullptr;
+ m_pModule = nullptr;
}
~CDetour()
@@ -47,7 +52,7 @@ class CDetour : public CDetourBase
FreeDetour();
}
- void CreateDetour();
+ bool CreateDetour(CGameConfig *gameConfig);
void EnableDetour();
void DisableDetour();
void FreeDetour() override;
@@ -66,6 +71,7 @@ class CDetour : public CDetourBase
T* m_pfnDetour;
const char* m_pszName;
byte* m_pSignature;
+ const char* m_pSymbol;
T* m_pfnFunc;
funchook_t* m_hook;
bool m_bInstalled;
@@ -74,24 +80,11 @@ class CDetour : public CDetourBase
extern CUtlVector g_vecDetours;
template
-void CDetour::CreateDetour()
+bool CDetour::CreateDetour(CGameConfig *gameConfig)
{
- if (!m_pModule || !(*m_pModule))
- {
- Panic("Invalid Module\n", m_pszName);
- return;
- }
-
- if (!m_pSignature)
- m_pfnFunc = (T*)dlsym((*m_pModule)->m_hModule, m_pszName);
- else
- m_pfnFunc = (T*)(*m_pModule)->FindSignature(m_pSignature);
-
+ m_pfnFunc = (T*)gameConfig->ResolveSignature(m_pszName);
if (!m_pfnFunc)
- {
- Panic("Could not find the address for %s to detour\n", m_pszName);
- return;
- }
+ return false;
m_hook = funchook_create();
funchook_prepare(m_hook, (void**)&m_pfnFunc, (void*)m_pfnDetour);
@@ -99,6 +92,7 @@ void CDetour::CreateDetour()
g_vecDetours.AddToTail(this);
Message("Successfully initialized detour for %s!\n", m_pszName);
+ return true;
}
template
@@ -144,7 +138,7 @@ void CDetour::FreeDetour()
Warning("funchook_destroy error for %s: %d %s\n", m_pszName, error, funchook_error_message(m_hook));
}
-#define DECLARE_DETOUR(name, detour, modulepath) \
- CDetour name(modulepath, detour, #name, (byte*)sigs::name)
+#define DECLARE_DETOUR(name, detour) \
+ CDetour name(detour, #name)
void FlushAllDetours();
diff --git a/src/common.h b/src/common.h
index daae513f..fc585160 100644
--- a/src/common.h
+++ b/src/common.h
@@ -47,8 +47,5 @@ void UnlockConVars();
void UnlockConCommands();
void ToggleLogs();
-void InitPatches();
-void UndoPatches();
-
void Message(const char *, ...);
void Panic(const char *, ...);
diff --git a/src/cs2_sdk/entity/cbaseentity.h b/src/cs2_sdk/entity/cbaseentity.h
index b94fcbf4..217fc8e9 100644
--- a/src/cs2_sdk/entity/cbaseentity.h
+++ b/src/cs2_sdk/entity/cbaseentity.h
@@ -24,9 +24,12 @@
#include "mathlib/vector.h"
#include "baseentity.h"
#include "ehandle.h"
+#include "../../gameconfig.h"
CGlobalVars* GetGameGlobals();
+extern CGameConfig *g_GameConfig;
+
class CNetworkTransmitComponent
{
public:
@@ -135,9 +138,9 @@ class Z_CBaseEntity : public CBaseEntity
Vector GetAbsOrigin() { return m_CBodyComponent->m_pSceneNode->m_vecAbsOrigin; }
void SetAbsOrigin(Vector vecOrigin) { m_CBodyComponent->m_pSceneNode->m_vecAbsOrigin = vecOrigin; }
- void Teleport(Vector *position, QAngle *angles, Vector *velocity) { CALL_VIRTUAL(void, offsets::Teleport, this, position, angles, velocity); }
+ void Teleport(Vector *position, QAngle *angles, Vector *velocity) { static int offset = g_GameConfig->GetOffset("Teleport"); CALL_VIRTUAL(void, offset, this, position, angles, velocity); }
- void CollisionRulesChanged() { CALL_VIRTUAL(void, offsets::CollisionRulesChanged, this); }
+ void CollisionRulesChanged() { static int offset = g_GameConfig->GetOffset("CollisionRulesChanged"); CALL_VIRTUAL(void, offset, this); }
CHandle GetHandle() { return m_pEntity->m_EHandle; }
diff --git a/src/cs2_sdk/interfaces/cgameresourceserviceserver.h b/src/cs2_sdk/interfaces/cgameresourceserviceserver.h
index 1138586f..c5cc30b3 100644
--- a/src/cs2_sdk/interfaces/cgameresourceserviceserver.h
+++ b/src/cs2_sdk/interfaces/cgameresourceserviceserver.h
@@ -20,15 +20,18 @@
#pragma once
#include
#include "interfaces/interfaces.h"
-#include "../../addresses.h"
+#include "../../gameconfig.h"
class CGameEntitySystem;
+extern CGameConfig *g_GameConfig;
+
class CGameResourceService
{
public:
CGameEntitySystem *GetGameEntitySystem()
{
- return *reinterpret_cast((uintptr_t)(this) + offsets::GameEntitySystem);
+ static int offset = g_GameConfig->GetOffset("GameEntitySystem");
+ return *reinterpret_cast((uintptr_t)(this) + offset);
}
-};
\ No newline at end of file
+};
diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp
index 183ed41c..4227623a 100644
--- a/src/cs2fixes.cpp
+++ b/src/cs2fixes.cpp
@@ -30,6 +30,7 @@
#include "common.h"
#include "commands.h"
#include "detours.h"
+#include "patches.h"
#include "icvar.h"
#include "interface.h"
#include "tier0/dbg.h"
@@ -42,6 +43,7 @@
#include
#include "adminsystem.h"
#include "eventlistener.h"
+#include "gameconfig.h"
#include "tier0/memdbgon.h"
@@ -129,11 +131,12 @@ CON_COMMAND_F(toggle_logs, "Toggle printing most logs and warnings", FCVAR_SPONL
}
IGameEventSystem* g_gameEventSystem;
-IGameEventManager2* g_gameEventManager;
+IGameEventManager2* g_gameEventManager = nullptr;
INetworkGameServer* g_networkGameServer;
CGlobalVars* gpGlobals = nullptr;
-CPlayerManager* g_playerManager;
+CPlayerManager* g_playerManager = nullptr;
IVEngineServer2* g_pEngineServer2;
+CGameConfig *g_GameConfig = nullptr;
PLUGIN_EXPOSE(CS2Fixes, g_CS2Fixes);
bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
@@ -166,8 +169,25 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool
SH_ADD_HOOK_MEMFUNC(INetworkServerService, StartupServer, g_pNetworkServerService, this, &CS2Fixes::Hook_StartupServer, true);
META_CONPRINTF( "All hooks started!\n" );
-
- addresses::Initialize();
+
+ 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);
+ char conf_error[255] = "";
+ if (!g_GameConfig->Init(g_pFullFileSystem, conf_error, sizeof(conf_error)))
+ {
+ snprintf(error, maxlen, "Could not read %s: %s", g_GameConfig->GetPath().c_str(), conf_error);
+ Panic("%s\n", error);
+ return false;
+ }
+
+ addresses::Initialize(g_GameConfig);
interfaces::Initialize();
UnlockConVars();
@@ -177,8 +197,16 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool
ConVar_Register(FCVAR_RELEASE | FCVAR_CLIENT_CAN_EXECUTE | FCVAR_GAMEDLL);
- InitPatches();
- InitDetours();
+ bool requiredInitLoaded = true;
+
+ if (!InitPatches(g_GameConfig))
+ requiredInitLoaded = false;
+
+ if (!InitDetours(g_GameConfig))
+ requiredInitLoaded = false;
+
+ if (!requiredInitLoaded)
+ return false;
g_playerManager = new CPlayerManager();
g_pAdminSystem = new CAdminSystem();
@@ -226,8 +254,14 @@ bool CS2Fixes::Unload(char *error, size_t maxlen)
RemoveTimers();
UnregisterEventListeners();
- delete g_playerManager;
- delete g_pAdminSystem;
+ if (g_playerManager != NULL)
+ delete g_playerManager;
+
+ if (g_pAdminSystem != NULL)
+ delete g_pAdminSystem;
+
+ if (g_GameConfig != NULL)
+ delete g_GameConfig;
return true;
}
@@ -256,6 +290,8 @@ void CS2Fixes::Hook_StartupServer(const GameSessionConfiguration_t& config, ISou
void CS2Fixes::Hook_PostEvent(CSplitScreenSlot nSlot, bool bLocalOnly, int nClientCount, const uint64* clients,
INetworkSerializable* pEvent, const void* pData, unsigned long nSize, NetChannelBufType_t bufType)
{
+ // Message( "Hook_PostEvent(%d, %d, %d, %lli)\n", nSlot, bLocalOnly, nClientCount, clients );
+
NetMessageInfo_t* info = pEvent->GetNetMessageInfo();
//CMsgTEFireBullets
@@ -288,6 +324,8 @@ void CS2Fixes::AllPluginsLoaded()
/* This is where we'd do stuff that relies on the mod or other plugins
* being initialized (for example, cvars added and events registered).
*/
+
+ Message( "AllPluginsLoaded\n" );
}
void CS2Fixes::Hook_ClientActive( CPlayerSlot slot, bool bLoadGame, const char *pszName, uint64 xuid )
@@ -307,17 +345,18 @@ void CS2Fixes::Hook_ClientSettingsChanged( CPlayerSlot slot )
void CS2Fixes::Hook_OnClientConnected( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, const char *pszAddress, bool bFakePlayer )
{
+ META_CONPRINTF( "Hook_OnClientConnected(%d, \"%s\", %lli, \"%s\", \"%s\", %d)\n", slot, pszName, xuid, pszNetworkID, pszAddress, bFakePlayer );
+
if(bFakePlayer)
g_playerManager->OnBotConnected(slot);
-
- META_CONPRINTF( "Hook_OnClientConnected(%d, \"%s\", %lli, \"%s\", \"%s\", %d)\n", slot, pszName, xuid, pszNetworkID, pszAddress, bFakePlayer );
}
bool CS2Fixes::Hook_ClientConnect( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason )
{
- g_playerManager->OnClientConnected(slot);
META_CONPRINTF( "Hook_ClientConnect(%d, \"%s\", %lli, \"%s\", %d, \"%s\")\n", slot, pszName, xuid, pszNetworkID, unk1, pRejectReason->ToGrowable()->Get() );
+ g_playerManager->OnClientConnected(slot);
+
RETURN_META_VALUE(MRES_IGNORED, true);
}
@@ -328,8 +367,9 @@ void CS2Fixes::Hook_ClientPutInServer( CPlayerSlot slot, char const *pszName, in
void CS2Fixes::Hook_ClientDisconnect( CPlayerSlot slot, int reason, const char *pszName, uint64 xuid, const char *pszNetworkID )
{
- g_playerManager->OnClientDisconnect(slot);
META_CONPRINTF( "Hook_ClientDisconnect(%d, %d, \"%s\", %lli, \"%s\")\n", slot, reason, pszName, xuid, pszNetworkID );
+
+ g_playerManager->OnClientDisconnect(slot);
}
void CS2Fixes::Hook_GameFrame( bool simulating, bool bFirstTick, bool bLastTick )
diff --git a/src/detours.cpp b/src/detours.cpp
index f5fdc354..683b4e3d 100644
--- a/src/detours.cpp
+++ b/src/detours.cpp
@@ -33,6 +33,7 @@
#include "entity/ctriggerpush.h"
#include "playermanager.h"
#include "igameevents.h"
+#include "gameconfig.h"
#include "tier0/memdbgon.h"
@@ -40,13 +41,13 @@ extern CGlobalVars *gpGlobals;
extern CEntitySystem *g_pEntitySystem;
extern IGameEventManager2 *g_gameEventManager;
-DECLARE_DETOUR(Host_Say, Detour_Host_Say, &modules::server);
-DECLARE_DETOUR(UTIL_SayTextFilter, Detour_UTIL_SayTextFilter, &modules::server);
-DECLARE_DETOUR(UTIL_SayText2Filter, Detour_UTIL_SayText2Filter, &modules::server);
-DECLARE_DETOUR(IsHearingClient, Detour_IsHearingClient, &modules::engine);
-DECLARE_DETOUR(CSoundEmitterSystem_EmitSound, Detour_CSoundEmitterSystem_EmitSound, &modules::server);
-DECLARE_DETOUR(CCSWeaponBase_Spawn, Detour_CCSWeaponBase_Spawn, &modules::server);
-DECLARE_DETOUR(TriggerPush_Touch, Detour_TriggerPush_Touch, &modules::server);
+DECLARE_DETOUR(Host_Say, Detour_Host_Say);
+DECLARE_DETOUR(UTIL_SayTextFilter, Detour_UTIL_SayTextFilter);
+DECLARE_DETOUR(UTIL_SayText2Filter, Detour_UTIL_SayText2Filter);
+DECLARE_DETOUR(IsHearingClient, Detour_IsHearingClient);
+DECLARE_DETOUR(CSoundEmitterSystem_EmitSound, Detour_CSoundEmitterSystem_EmitSound);
+DECLARE_DETOUR(CCSWeaponBase_Spawn, Detour_CCSWeaponBase_Spawn);
+DECLARE_DETOUR(TriggerPush_Touch, Detour_TriggerPush_Touch);
void FASTCALL Detour_TriggerPush_Touch(CTriggerPush* pPush, Z_CBaseEntity* pOther)
{
@@ -216,18 +217,18 @@ bool FASTCALL Detour_IsChannelEnabled(LoggingChannelID_t channelID, LoggingSever
CDetour g_LoggingDetours[] =
{
- CDetour(&modules::tier0, Detour_Log, "Msg" ),
- //CDetour( modules::tier0, Detour_Log, "?ConMsg@@YAXPEBDZZ" ),
- //CDetour( modules::tier0, Detour_Log, "?ConColorMsg@@YAXAEBVColor@@PEBDZZ" ),
- CDetour( &modules::tier0, Detour_Log, "ConDMsg" ),
- CDetour( &modules::tier0, Detour_Log, "DevMsg" ),
- CDetour( &modules::tier0, Detour_Log, "Warning" ),
- CDetour( &modules::tier0, Detour_Log, "DevWarning" ),
- //CDetour( modules::tier0, Detour_Log, "?DevWarning@@YAXPEBDZZ" ),
- CDetour( &modules::tier0, Detour_Log, "LoggingSystem_Log" ),
- CDetour( &modules::tier0, Detour_Log, "LoggingSystem_LogDirect" ),
- CDetour( &modules::tier0, Detour_Log, "LoggingSystem_LogAssert" ),
- //CDetour( modules::tier0, Detour_IsChannelEnabled, "LoggingSystem_IsChannelEnabled" ),
+ CDetour( Detour_Log, "Msg" ),
+ //CDetour( Detour_Log, "?ConMsg@@YAXPEBDZZ" ),
+ //CDetour( Detour_Log, "?ConColorMsg@@YAXAEBVColor@@PEBDZZ" ),
+ CDetour( Detour_Log, "ConDMsg" ),
+ CDetour( Detour_Log, "DevMsg" ),
+ CDetour( Detour_Log, "Warning" ),
+ CDetour( Detour_Log, "DevWarning" ),
+ //CDetour( Detour_Log, "?DevWarning@@YAXPEBDZZ" ),
+ CDetour( Detour_Log, "LoggingSystem_Log" ),
+ CDetour( Detour_Log, "LoggingSystem_LogDirect" ),
+ CDetour( Detour_Log, "LoggingSystem_LogAssert" ),
+ //CDetour( Detour_IsChannelEnabled, "LoggingSystem_IsChannelEnabled" ),
};
void ToggleLogs()
@@ -250,33 +251,47 @@ void ToggleLogs()
CUtlVector g_vecDetours;
-void InitDetours()
+bool InitDetours(CGameConfig *gameConfig)
{
+ bool success = true;
+
g_vecDetours.PurgeAndDeleteElements();
for (int i = 0; i < sizeof(g_LoggingDetours) / sizeof(*g_LoggingDetours); i++)
- g_LoggingDetours[i].CreateDetour();
+ {
+ if (!g_LoggingDetours[i].CreateDetour(gameConfig))
+ success = false;
+ }
- UTIL_SayTextFilter.CreateDetour();
+ if (!UTIL_SayTextFilter.CreateDetour(gameConfig))
+ success = false;
UTIL_SayTextFilter.EnableDetour();
- UTIL_SayText2Filter.CreateDetour();
+ if (!UTIL_SayText2Filter.CreateDetour(gameConfig))
+ success = false;
UTIL_SayText2Filter.EnableDetour();
- Host_Say.CreateDetour();
+ if (!Host_Say.CreateDetour(gameConfig))
+ success = false;
Host_Say.EnableDetour();
- IsHearingClient.CreateDetour();
+ if (!IsHearingClient.CreateDetour(gameConfig))
+ success = false;
IsHearingClient.EnableDetour();
- CSoundEmitterSystem_EmitSound.CreateDetour();
+ if (!CSoundEmitterSystem_EmitSound.CreateDetour(gameConfig))
+ success = false;
CSoundEmitterSystem_EmitSound.EnableDetour();
- CCSWeaponBase_Spawn.CreateDetour();
+ if (!CCSWeaponBase_Spawn.CreateDetour(gameConfig))
+ success = false;
CCSWeaponBase_Spawn.EnableDetour();
- TriggerPush_Touch.CreateDetour();
+ if (!TriggerPush_Touch.CreateDetour(gameConfig))
+ success = false;
TriggerPush_Touch.EnableDetour();
+
+ return success;
}
void FlushAllDetours()
diff --git a/src/detours.h b/src/detours.h
index 7ffaf7a6..c400ac61 100644
--- a/src/detours.h
+++ b/src/detours.h
@@ -28,8 +28,9 @@ class CCSPlayerController;
class CEntityIndex;
class CCommand;
class CTriggerPush;
+class CGameConfig;
-void InitDetours();
+bool InitDetours(CGameConfig *gameConfig);
void FlushAllDetours();
void FASTCALL Detour_UTIL_SayTextFilter(IRecipientFilter &, const char *, CCSPlayerController *, uint64);
diff --git a/src/events.cpp b/src/events.cpp
index 2c1e8094..dbaf4130 100644
--- a/src/events.cpp
+++ b/src/events.cpp
@@ -34,6 +34,9 @@ CUtlVector g_vecEventListeners;
void RegisterEventListeners()
{
+ if (!g_gameEventManager)
+ return;
+
FOR_EACH_VEC(g_vecEventListeners, i)
{
g_gameEventManager->AddListener(g_vecEventListeners[i], g_vecEventListeners[i]->GetEventName(), true);
@@ -42,6 +45,9 @@ void RegisterEventListeners()
void UnregisterEventListeners()
{
+ if (!g_gameEventManager)
+ return;
+
FOR_EACH_VEC(g_vecEventListeners, i)
{
g_gameEventManager->RemoveListener(g_vecEventListeners[i]);
diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp
new file mode 100644
index 00000000..92cdbb9f
--- /dev/null
+++ b/src/gameconfig.cpp
@@ -0,0 +1,260 @@
+#include "gameconfig.h"
+#include "addresses.h"
+
+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::~CGameConfig()
+{
+ delete m_pKeyValues;
+}
+
+bool CGameConfig::Init(IFileSystem *filesystem, char *conf_error, int conf_error_size)
+{
+ if (!m_pKeyValues->LoadFromFile(filesystem, m_szPath.c_str(), nullptr))
+ {
+ snprintf(conf_error, conf_error_size, "Failed to load gamedata file");
+ return false;
+ }
+
+ const KeyValues* game = m_pKeyValues->FindKey(m_szGameDir.c_str());
+ if (game)
+ {
+#if defined _LINUX
+ const char* platform = "linux";
+#else
+ const char* platform = "windows";
+#endif
+
+ const KeyValues* offsets = game->FindKey("Offsets");
+ if (offsets)
+ {
+ FOR_EACH_SUBKEY(offsets, it)
+ {
+ m_umOffsets[it->GetName()] = it->GetInt(platform, -1);
+ }
+ }
+
+ const KeyValues* signatures = game->FindKey("Signatures");
+ if (signatures)
+ {
+ FOR_EACH_SUBKEY(signatures, it)
+ {
+ m_umLibraries[it->GetName()] = std::string(it->GetString("library"));
+ m_umSignatures[it->GetName()] = std::string(it->GetString(platform));
+ }
+ }
+
+ const KeyValues* patches = game->FindKey("Patches");
+ if (patches)
+ {
+ FOR_EACH_SUBKEY(patches, it)
+ {
+ m_umPatches[it->GetName()] = std::string(it->GetString(platform));
+ }
+ }
+ }
+ 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;
+}
+
+const char *CGameConfig::GetSignature(const std::string& name)
+{
+ auto it = m_umSignatures.find(name);
+ if (it == m_umSignatures.end())
+ {
+ return nullptr;
+ }
+ return it->second.c_str();
+}
+
+const char *CGameConfig::GetPatch(const std::string& name)
+{
+ auto it = m_umPatches.find(name);
+ if (it == m_umPatches.end())
+ {
+ return nullptr;
+ }
+ return it->second.c_str();
+}
+
+int CGameConfig::GetOffset(const std::string& name)
+{
+ auto it = m_umOffsets.find(name);
+ if (it == m_umOffsets.end())
+ {
+ return -1;
+ }
+ return it->second;
+}
+
+const char *CGameConfig::GetLibrary(const std::string& name)
+{
+ auto it = m_umLibraries.find(name);
+ if (it == m_umLibraries.end())
+ {
+ return nullptr;
+ }
+ return it->second.c_str();
+}
+
+CModule **CGameConfig::GetModule(const char *name)
+{
+ const char *library = this->GetLibrary(name);
+ if (library == NULL)
+ return NULL;
+
+ if (strcmp(library, "engine") == 0)
+ return &modules::engine;
+ else if (strcmp(library, "server") == 0)
+ return &modules::server;
+ else if (strcmp(library, "client") == 0)
+ return &modules::client;
+ else if (strcmp(library, "vscript") == 0)
+ return &modules::vscript;
+ else if (strcmp(library, "tier0") == 0)
+ return &modules::tier0;
+#ifdef _WIN32
+ else if (strcmp(library, "hammer") == 0)
+ return &modules::hammer;
+#endif
+ return NULL;
+}
+
+bool CGameConfig::IsSymbol(const char *name)
+{
+ const char *sigOrSymbol = this->GetSignature(name);
+ if (sigOrSymbol == NULL || strlen(sigOrSymbol) <= 0)
+ {
+ Panic("Missing signature or symbol\n", name);
+ return false;
+ }
+ return sigOrSymbol[0] == '@';
+}
+
+const char* CGameConfig::GetSymbol(const char *name)
+{
+ const char *symbol = this->GetSignature(name);
+
+ if (symbol == NULL || strlen(symbol) <= 1)
+ {
+ Panic("Missing symbol\n", name);
+ return NULL;
+ }
+ return symbol + 1;
+}
+
+void *CGameConfig::ResolveSignature(const char *name)
+{
+ CModule **module = this->GetModule(name);
+ if (!module || !(*module))
+ {
+ Panic("Invalid Module %s\n", name);
+ return NULL;
+ }
+
+ void *address = nullptr;
+ if (this->IsSymbol(name))
+ {
+ const char *symbol = this->GetSymbol(name);
+ if (symbol == NULL)
+ {
+ Panic("Invalid symbol for %s\n", name);
+ return NULL;
+ }
+ address = dlsym((*module)->m_hModule, symbol);
+ }
+ else
+ {
+ const char *signature = this->GetSignature(name);
+ if (signature == NULL)
+ {
+ Panic("Failed to find signature for %s\n", name);
+ return NULL;
+ }
+
+ byte *pSignature = CGameConfig::HexToByte(signature);
+ if (pSignature == NULL)
+ return NULL;
+ address = (*module)->FindSignature(pSignature);
+ }
+
+ if (address == NULL)
+ {
+ Panic("Failed to find address for %s\n", name);
+ return NULL;
+ }
+ return address;
+}
+
+// Static functions
+std::string CGameConfig::GetDirectoryName(const std::string &directoryPathInput)
+{
+ std::string directoryPath = std::string(directoryPathInput);
+
+ size_t found = std::string(directoryPath).find_last_of("/\\");
+ if (found != std::string::npos)
+ {
+ return std::string(directoryPath, found + 1);
+ }
+ return "";
+}
+
+int CGameConfig::HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes)
+{
+ if (hexString == NULL) {
+ printf("Invalid hex string.\n");
+ return -1;
+ }
+
+ size_t hexStringLength = strlen(hexString);
+ size_t byteCount = hexStringLength / 4; // Each "\\x" represents one byte.
+
+ if (hexStringLength % 4 != 0 || byteCount == 0 || byteCount > maxBytes) {
+ printf("Invalid hex string format or byte count.\n");
+ return -1; // Return an error code.
+ }
+
+ for (size_t i = 0; i < hexStringLength; i += 4) {
+ if (sscanf(hexString + i, "\\x%2hhX", &byteArray[i / 4]) != 1) {
+ printf("Failed to parse hex string at position %zu.\n", i);
+ return -1; // Return an error code.
+ }
+ }
+
+ byteArray[byteCount] = '\0'; // Add a null-terminating character.
+
+ return byteCount; // Return the number of bytes successfully converted.
+}
+
+byte *CGameConfig::HexToByte(const char *src)
+{
+ if (src == NULL || strlen(src) <= 0)
+ {
+ Panic("Invalid hex string\n");
+ return NULL;
+ }
+
+ size_t maxBytes = strlen(src) / 4;
+ uint8_t *dest = new uint8_t[maxBytes];
+ int byteCount = CGameConfig::HexStringToUint8Array(src, dest, maxBytes);
+ if (byteCount <= 0)
+ {
+ Panic("Invalid hex format %s\n", src);
+ return NULL;
+ }
+ return (byte *)dest;
+}
diff --git a/src/gameconfig.h b/src/gameconfig.h
new file mode 100644
index 00000000..80360635
--- /dev/null
+++ b/src/gameconfig.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "KeyValues.h"
+
+#include
+#include
+
+class CModule;
+
+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();
+ const char *GetLibrary(const std::string& name);
+ const char *GetSignature(const std::string& name);
+ const char* GetSymbol(const char *name);
+ const char *GetPatch(const std::string& name);
+ int GetOffset(const std::string& name);
+ void* GetAddress(const std::string& name, void *engine, void *server, char *error, int maxlen);
+ 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);
+
+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;
+ std::unordered_map m_umLibraries;
+ std::unordered_map m_umPatches;
+};
diff --git a/src/mempatch.cpp b/src/mempatch.cpp
index 83bfe181..a74c47ed 100644
--- a/src/mempatch.cpp
+++ b/src/mempatch.cpp
@@ -25,18 +25,22 @@
#include "tier0/memdbgon.h"
-void CMemPatch::PerformPatch()
+bool CMemPatch::PerformPatch(CGameConfig *gameConfig)
{
- if (!m_pModule)
- return;
-
- m_pPatchAddress = (*m_pModule)->FindSignature(m_pSignature);
+ m_pPatchAddress = gameConfig->ResolveSignature(m_pSignatureName);
+ if (m_pPatchAddress == NULL)
+ return false;
- if (!m_pPatchAddress)
+ const char *patch = gameConfig->GetPatch(m_pszName);
+ if (patch == NULL)
{
- Panic("Failed to find signature for %s\n", m_pszName);
- return;
+ Panic("Failed to find patch for %s\n", m_pszName);
+ return false;
}
+ m_pPatch = gameConfig->HexToByte(patch);
+ if (m_pPatch == NULL)
+ return false;
+ m_iPatchLength = V_strlen((char*)m_pPatch);
m_pOriginalBytes = new byte[m_iPatchLength];
V_memcpy(m_pOriginalBytes, m_pPatchAddress, m_iPatchLength);
@@ -44,6 +48,7 @@ void CMemPatch::PerformPatch()
Plat_WriteMemory(m_pPatchAddress, (byte*)m_pPatch, m_iPatchLength);
Message("Successfully patched %s at %p\n", m_pszName, m_pPatchAddress);
+ return true;
}
void CMemPatch::UndoPatch()
diff --git a/src/mempatch.h b/src/mempatch.h
index 2c594770..7524fd4d 100644
--- a/src/mempatch.h
+++ b/src/mempatch.h
@@ -21,19 +21,23 @@
#include "platform.h"
#include "utils/module.h"
+#include "gameconfig.h"
class CMemPatch
{
public:
- CMemPatch(CModule **pModule, const byte *pSignature, const byte *pPatch, const char *pszName, int iRepeat = 1) :
- m_pModule(pModule), m_pSignature(pSignature), m_pPatch(pPatch), m_pszName(pszName), m_iRepeat(iRepeat)
+ CMemPatch(const char *pSignatureName, const char *pszName, int iRepeat = 1) :
+ m_pSignatureName(pSignatureName), m_pszName(pszName), m_iRepeat(iRepeat)
{
+ m_pModule = nullptr;
m_pPatchAddress = nullptr;
- m_pOriginalBytes = nullptr;
- m_iPatchLength = V_strlen((char*)m_pPatch);
+ m_pOriginalBytes = nullptr;
+ m_pSignature = nullptr;
+ m_pPatch = nullptr;
+ m_iPatchLength = 0;
}
- void PerformPatch();
+ bool PerformPatch(CGameConfig *gameConfig);
void UndoPatch();
void *GetPatchAddress() { return m_pPatchAddress; }
@@ -43,6 +47,7 @@ class CMemPatch
const byte *m_pSignature;
const byte *m_pPatch;
byte *m_pOriginalBytes;
+ const char *m_pSignatureName;
const char *m_pszName;
int m_iRepeat;
int m_iPatchLength;
diff --git a/src/patches.cpp b/src/patches.cpp
index b2932cdf..d39eda91 100644
--- a/src/patches.cpp
+++ b/src/patches.cpp
@@ -26,39 +26,47 @@
#include "entity/ccsplayerpawn.h"
#include "entity/cbasemodelentity.h"
#include "addresses.h"
+#include "patches.h"
#include "tier0/memdbgon.h"
CMemPatch g_CommonPatches[] =
{
- CMemPatch(&modules::server, sigs::MovementUnlock, sigs::Patch_MovementUnlock, "ServerMovementUnlock"),
- CMemPatch(&modules::vscript, sigs::VScriptEnable, sigs::Patch_VScriptEnable, "VScriptEnable"),
- CMemPatch(&modules::server, sigs::CheckJumpButtonWater, sigs::Patch_CheckJumpButton, "FixWaterFloorJump"),
+ CMemPatch("ServerMovementUnlock", "ServerMovementUnlock"),
+ CMemPatch("VScriptEnable", "VScriptEnable"),
+ CMemPatch("CheckJumpButtonWater", "FixWaterFloorJump"),
};
CMemPatch g_ClientPatches[] =
{
- CMemPatch(&modules::client, sigs::MovementUnlock, sigs::Patch_MovementUnlock, "ClientMovementUnlock"),
+ CMemPatch("ClientMovementUnlock", "ClientMovementUnlock"),
};
#ifdef _WIN32
CMemPatch g_ToolsPatches[] =
{
// Remove some -nocustomermachine checks without needing -nocustomermachine itself as it can break stuff, mainly to enable device selection in compiles
- CMemPatch(&modules::hammer, sigs::HammerNoCustomerMachine, sigs::Patch_HammerNoCustomerMachine, "HammerNoCustomerMachine", 4),
+ CMemPatch("HammerNoCustomerMachine", "HammerNoCustomerMachine", 4),
};
#endif
-void InitPatches()
+bool InitPatches(CGameConfig *g_GameConfig)
{
+ bool success = true;
for (int i = 0; i < sizeof(g_CommonPatches) / sizeof(*g_CommonPatches); i++)
- g_CommonPatches[i].PerformPatch();
+ {
+ if (!g_CommonPatches[i].PerformPatch(g_GameConfig))
+ success = false;
+ }
// Dedicated servers don't load client
if (!CommandLine()->HasParm("-dedicated"))
{
for (int i = 0; i < sizeof(g_ClientPatches) / sizeof(*g_ClientPatches); i++)
- g_ClientPatches[i].PerformPatch();
+ {
+ if (!g_ClientPatches[i].PerformPatch(g_GameConfig))
+ success = false;
+ }
}
#ifdef _WIN32
@@ -66,9 +74,13 @@ void InitPatches()
if (CommandLine()->HasParm("-tools"))
{
for (int i = 0; i < sizeof(g_ToolsPatches) / sizeof(*g_ToolsPatches); i++)
- g_ToolsPatches[i].PerformPatch();
+ {
+ if (!g_ToolsPatches[i].PerformPatch(g_GameConfig))
+ success = false;
+ }
}
#endif
+ return success;
}
void UndoPatches()
diff --git a/src/patches.h b/src/patches.h
new file mode 100644
index 00000000..255b64b4
--- /dev/null
+++ b/src/patches.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "gameconfig.h"
+
+bool InitPatches(CGameConfig *gameConfig);
+void UndoPatches();