diff --git a/.gitmodules b/.gitmodules
index 77548434b..096b58f94 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,7 @@
[submodule "sdk"]
path = sdk
url = https://github.com/alliedmodders/hl2sdk.git
+ branch = cs2
[submodule "hl2sdk-manifests"]
path = hl2sdk-manifests
url = https://github.com/alliedmodders/hl2sdk-manifests
diff --git a/AMBuildScript b/AMBuildScript
index 7e67b9ba4..eb9bcac73 100644
--- a/AMBuildScript
+++ b/AMBuildScript
@@ -438,7 +438,7 @@ const char *PLUGIN_FULL_VERSION = \"{version}\";
cxx.cxxincludes += [
os.path.join(context.currentSourcePath),
os.path.join(mms_core_path),
- os.path.join(mms_core_path, 'sourcehook'),
+ os.path.join(self.mms_root, 'third_party', 'khook', 'include'),
]
for other_sdk in self.sdk_manifests:
diff --git a/AMBuilder b/AMBuilder
index 7fb0fa26f..66d4347d9 100644
--- a/AMBuilder
+++ b/AMBuilder
@@ -13,23 +13,16 @@ for sdk_target in MMSPlugin.sdk_targets:
os.path.join(builder.sourcePath, 'src', 'utils'),
os.path.join(builder.sourcePath, 'public'),
os.path.join(builder.sourcePath, 'sdk', 'thirdparty', 'protobuf-3.21.8', 'src'),
- os.path.join(builder.sourcePath, 'vendor', 'funchook', 'include'),
]
- target_folder = 'Debug' if builder.options.debug else 'Release'
-
if binary.compiler.target.platform == 'linux':
binary.compiler.postlink += [
- os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'libfunchook.a'),
- os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'libdistorm.a'),
os.path.join(builder.sourcePath, 'sdk', 'lib', 'linux64', 'release', 'libprotobuf.a'),
]
binary.sources += ['src/utils/plat_unix.cpp']
elif binary.compiler.target.platform == 'windows':
binary.compiler.postlink += [
os.path.join('psapi.lib'),
- os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'funchook.lib'),
- os.path.join(builder.sourcePath, 'vendor', 'funchook', 'lib', target_folder, 'distorm.lib'),
os.path.join(builder.sourcePath, 'sdk', 'lib' ,'public', 'win64', '2015', 'libprotobuf.lib'),
os.path.join(builder.sourcePath, 'sdk', 'lib', 'public', 'win64', 'steam_api64.lib')
]
@@ -44,6 +37,7 @@ for sdk_target in MMSPlugin.sdk_targets:
'src/commands.cpp',
'src/addresses.cpp',
'src/detours.cpp',
+ 'src/virtual_hooks.cpp',
'src/entities.cpp',
'src/events.cpp',
'src/utils/entity.cpp',
@@ -52,6 +46,7 @@ for sdk_target in MMSPlugin.sdk_targets:
'src/utils/utils.cpp',
'src/utils/vscript_function.cpp',
'src/cs2_sdk/entity/services.cpp',
+ 'src/cs2_sdk/entity/customhudlayout.cpp',
'src/cs2_sdk/schema.cpp',
'src/ctimer.cpp',
'src/panoramavote.cpp',
diff --git a/CS2Fixes.vcxproj b/CS2Fixes.vcxproj
index 85d63b9b7..797abd0e6 100644
--- a/CS2Fixes.vcxproj
+++ b/CS2Fixes.vcxproj
@@ -73,12 +73,12 @@
cs2fixes
- sdk\lib\public\win64;vendor/funchook/lib;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)
+ sdk\lib\public\win64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)
$(SolutionDir)/package/addons/cs2fixes/bin/win64/
cs2fixes
- sdk\lib\public\win64;vendor/funchook/lib;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)
+ sdk\lib\public\win64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)
$(SolutionDir)/package/addons/cs2fixes/bin/win64/
@@ -119,12 +119,12 @@
Level3
true
- __STDC_LIMIT_MACROS;X64BITS;WIN32;COMPILER_MSVC;COMPILER_MSVC64;_CRT_NO_VA_START_VALIDATION;_ITERATOR_DEBUG_LEVEL=0;_DEBUG;CS2Fixes_EXPORTS;_WINDOWS;_USRDLL;META_IS_SOURCE2;SUBHOOK_STATIC;%(PreprocessorDefinitions)
+ __STDC_LIMIT_MACROS;X64BITS;WIN32;COMPILER_MSVC;COMPILER_MSVC64;_CRT_NO_VA_START_VALIDATION;_ITERATOR_DEBUG_LEVEL=0;_DEBUG;CS2Fixes_EXPORTS;_WINDOWS;_USRDLL;META_IS_SOURCE2;%(PreprocessorDefinitions)
true
NotUsing
pch.h
stdcpp20
- build/cs2fixes.cs2/windows-x86_64;src/utils;src/cs2_sdk;sdk/public;sdk/public/tier0;sdk/game/shared;sdk/game/server;sdk/public/tier1;sdk/public/mathlib;minhook/include;$(MMSOURCE112)/core;$(MMSOURCE112)/core/sourcehook;$(MMSOURCE_DEV)/core;$(MMSOURCE_DEV)/core/sourcehook;vendor/subhook;vendor/funchook/include;sdk/public/entity2;sdk/public/game/server;sdk/thirdparty/protobuf-3.21.8/src;$(SolutionDir);%(AdditionalIncludeDirectories)
+ build/cs2fixes.cs2/windows-x86_64;src/utils;src/cs2_sdk;sdk/public;sdk/public/tier0;sdk/game/shared;sdk/game/server;sdk/public/tier1;sdk/public/mathlib;$(MMSOURCE112)/core;$(MMSOURCE112)/third_party/khook/include;$(MMSOURCE_DEV)/core;$(MMSOURCE_DEV)/third_party/khook/include;sdk/public/entity2;sdk/public/game/server;sdk/thirdparty/protobuf-3.21.8/src;$(SolutionDir);%(AdditionalIncludeDirectories)
%(UndefinePreprocessorDefinitions)
MultiThreadedDebug
true
@@ -133,8 +133,8 @@
Windows
true
false
- interfaces.lib;mathlib.lib;tier0.lib;tier1.lib;psapi.lib;funchook.lib;distorm.lib;steam_api64.lib;vendor/protobuf-lib/Debug/libprotobufd.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
- sdk/lib/public/win64;vendor/funchook/lib/Debug;%(AdditionalLibraryDirectories)
+ interfaces.lib;mathlib.lib;tier0.lib;tier1.lib;psapi.lib;steam_api64.lib;vendor/protobuf-lib/Debug/libprotobufd.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+ sdk/lib/public/win64;%(AdditionalLibraryDirectories)
@@ -145,12 +145,12 @@
true
true
true
- __STDC_LIMIT_MACROS;X64BITS;WIN32;COMPILER_MSVC;COMPILER_MSVC64;_CRT_NO_VA_START_VALIDATION;_ITERATOR_DEBUG_LEVEL=0;NDEBUG;_WINDOWS;CS2Fixes_EXPORTS;_USRDLL;META_IS_SOURCE2;SUBHOOK_STATIC;%(PreprocessorDefinitions)
+ __STDC_LIMIT_MACROS;X64BITS;WIN32;COMPILER_MSVC;COMPILER_MSVC64;_CRT_NO_VA_START_VALIDATION;_ITERATOR_DEBUG_LEVEL=0;NDEBUG;_WINDOWS;CS2Fixes_EXPORTS;_USRDLL;META_IS_SOURCE2;%(PreprocessorDefinitions)
Default
NotUsing
pch.h
stdcpp20
- build/cs2fixes.cs2/windows-x86_64;src/utils;src/cs2_sdk;sdk/public;sdk/public/tier0;sdk/game/shared;sdk/game/server;sdk/public/tier1;sdk/public/mathlib;minhook/include;$(MMSOURCE112)/core;$(MMSOURCE112)/core/sourcehook;$(MMSOURCE_DEV)/core;$(MMSOURCE_DEV)/core/sourcehook;vendor/subhook;vendor/funchook/include;sdk/public/entity2;sdk/public/game/server;sdk/thirdparty/protobuf-3.21.8/src;$(SolutionDir);%(AdditionalIncludeDirectories)
+ build/cs2fixes.cs2/windows-x86_64;src/utils;src/cs2_sdk;sdk/public;sdk/public/tier0;sdk/game/shared;sdk/game/server;sdk/public/tier1;sdk/public/mathlib;$(MMSOURCE112)/core;$(MMSOURCE112)/third_party/khook/include;$(MMSOURCE_DEV)/core;$(MMSOURCE_DEV)/third_party/khook/include;sdk/public/entity2;sdk/public/game/server;sdk/thirdparty/protobuf-3.21.8/src;$(SolutionDir);%(AdditionalIncludeDirectories)
MultiThreaded
%(UndefinePreprocessorDefinitions)
true
@@ -161,8 +161,8 @@
true
true
false
- interfaces.lib;mathlib.lib;tier0.lib;tier1.lib;psapi.lib;funchook.lib;distorm.lib;steam_api64.lib;vendor/protobuf-lib/Release/libprotobuf.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
- sdk/lib/public/win64;vendor/funchook/lib/Release;%(AdditionalLibraryDirectories)
+ interfaces.lib;mathlib.lib;tier0.lib;tier1.lib;psapi.lib;steam_api64.lib;vendor/protobuf-lib/Release/libprotobuf.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
+ sdk/lib/public/win64;%(AdditionalLibraryDirectories)
@@ -194,6 +194,7 @@
+
@@ -225,6 +226,7 @@
+
@@ -258,6 +260,8 @@
+
+
@@ -267,10 +271,11 @@
-
+
+
@@ -308,6 +313,7 @@
+
diff --git a/CS2Fixes.vcxproj.filters b/CS2Fixes.vcxproj.filters
index 12b823713..d03d6a9b1 100644
--- a/CS2Fixes.vcxproj.filters
+++ b/CS2Fixes.vcxproj.filters
@@ -68,6 +68,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -200,6 +203,9 @@
Source Files\cs2_sdk\entity
+
+ Source Files\cs2_sdk\entity
+
Source Files
@@ -268,15 +274,15 @@
Header Files
-
- Header Files
-
Header Files
Header Files
+
+ Header Files
+
Header Files
@@ -406,6 +412,9 @@
Header Files\cs2_sdk
+
+ Header Files\cs2_sdk
+
Header Files
@@ -442,6 +451,9 @@
Header Files\utils
+
+ Header Files\utils
+
Header Files\cs2_sdk\entity
@@ -451,5 +463,11 @@
Header Files
+
+ Header Files\cs2_sdk\entity
+
+
+ Header Files\cs2_sdk\entity
+
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index a68009bc3..e080113ac 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,7 +2,7 @@ FROM ghcr.io/source2ze/build-containers:steamrt3
WORKDIR /app
-RUN git clone https://github.com/alliedmodders/metamod-source
+RUN git clone --recurse-submodules https://github.com/alliedmodders/metamod-source
RUN git config --global --add safe.directory /app
COPY ./docker-entrypoint.sh ./
diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg
index 847f0545f..8d400411b 100644
--- a/cfg/cs2fixes/cs2fixes.cfg
+++ b/cfg/cs2fixes/cs2fixes.cfg
@@ -28,6 +28,7 @@ cs2f_cvarwhitelist_enable 0 // Whether to enable the custom ConVar whitelist f
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_allow_duck_spam 0 // Whether to allow duck spamming by removing the duck slowdown, clients will only partially predict [0 = disabled, 1 = both teams, 2 = T only, 3 = CT only]
+cs2f_thirdperson_enable 0 // Whether to enable thirdperson
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
@@ -71,7 +72,7 @@ cs2f_topdefender_print 1 // Whether to print defender stats to console at rou
cs2f_topdefender_score 5000 // Score given to the top defender
cs2f_topdefender_threshold 1000 // Damage threshold for Top Defenders to be shown on round end
cs2f_topdefender_rate 1.0 // How often TopDefender stats get updated
-cs2f_topdefender_clantag "[Top Defender]" // Clan tag given to the top defender
+cs2f_topdefender_clantag "Top Defender" // Clan tag given to the top defender
// Chat flood settings
cs2f_flood_interval 0.75 // Amount of time allowed between chat messages acquiring flood tokens
@@ -155,14 +156,12 @@ cs2f_idle_kick_min_players 0 // Minimum amount of connected clients to kick id
cs2f_idle_kick_admins 1 // Whether to kick idle players with ADMFLAG_GENERIC
// Button watch
-cs2f_enable_button_watch 0 // INCOMPATIBLE WITH CS#. Whether to enable button watch or not.
+cs2f_enable_button_watch 0 // Whether to enable button watch or not.
// EntWatch Settings
-entwatch_enable 0 // INCOMPATIBLE WITH CS#. Whether to enable EntWatch features
+entwatch_enable 0 // Whether to enable EntWatch features
entwatch_auto_filter 1 // Whether to automatically block non-item holders from triggering uses
entwatch_clantag 1 // Whether to set item holder's clantag and set 9999 score
-entwatch_clantag_colour_mode 1 // Whether to set item clantag colours (0=No colour, 1=Use item colour, 2=Use entwatch_clantag_colour value)
-entwatch_clantag_colour "FFFFFF" // Hex colour (RRGGBB) to use if entwatch_clantag_colour_mode 2
entwatch_hud 1 // Whether to enable the EntWatch hud and related commands
entwatch_score 9999 // Score to give item holders (0 = dont change score at all) Requires entwatch_clantag 1
entwatch_glow 1000 // Distance that dropped item weapon glow will be visible (0 = glow disabled)
@@ -175,4 +174,5 @@ cs2f_hud_duration_leeway 2 // Extra seconds duration to leave hud messages vis
// 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]
-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
+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]
+cs2f_mapmigrations_20260922 2 // Current mode for 2026-09-22 CS2 update map migrations. [0 = Force disabled, 1 = Force enabled, 2 = Automatically enabled for maps updated before 2026-09-22 & disabled if updated after]
\ No newline at end of file
diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc
index 5f4784bda..508ccd738 100644
--- a/gamedata/cs2fixes.jsonc
+++ b/gamedata/cs2fixes.jsonc
@@ -5,15 +5,15 @@
"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"
+ "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 D8",
+ "linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 41 56 4C 8D 75 ? 41 55 41 89 CD"
},
// 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"
+ "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 ? ? ? ? 41 8B D8",
+ "linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 41 89 D7 31 D2"
},
// idk a good way to find this again, i just brute forced the vtable. offset is 136 on CTriggerPush
"TriggerPush_Touch":
@@ -27,14 +27,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 49 89 FF 41 56 41 55 41 54 49 89 D4 53 48 89 F3 48 81 EC"
+ "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 ? ? ? ? 8B 97"
},
// 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 25 ? ? ? ? F3 0F 11 A5 ? ? ? ? 48 89 DE"
+ "linux": "76 ? F3 0F 51 C0 F3 0F 7E DB 49 8B 06"
},
// String: "CCSPlayerPawnBase::SwitchTeam", just keep in mind this is actually CCSPlayerController::SwitchTeam
"CCSPlayerController_SwitchTeam":
@@ -47,28 +47,28 @@
"CheckJumpButtonWater":
{
"library": "server",
- "windows": "C8 42 EB ? 4C 8B 77 ? 4D 39 66",
- "linux": "C8 42 41 C7 85 ? ? ? ? ? ? ? ? 41 C7 85 ? ? ? ? ? ? ? ? E9"
+ "windows": "C8 42 EB ? 4C 8B 73 ? 4D 39 6E",
+ "linux": "C8 42 41 C7 84 24 ? ? ? ? ? ? ? ? 41 C7 84 24 ? ? ? ? ? ? ? ? E9"
},
// "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",
+ "windows": "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 49 8B F1 48 8B F9",
"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 E5 41 56 49 89 FE 41 55 48 8D 7D"
+ "windows": "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 81 EC ? ? ? ? 4D 8B F0 48 8B F1",
+ "linux": "55 48 89 E5 41 57 49 89 FF 41 56 48 8D BD ? ? ? ? 41 55 4C 8D AD"
},
// 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 6C 24 ? 48 81 EC ? ? ? ? 48 8B 02",
+ "windows": "48 89 54 24 ? 48 89 4C 24 ? 55 53 56 57 41 55 41 56 41 57 48 8D 6C 24",
"linux": "55 48 89 E5 41 57 41 56 4C 8D BD ? ? ? ? 4D 89 CE"
},
// func_pushable inside CTriggerBrush::Use calls CEntityIOOutput::FireOutputInternal
@@ -78,8 +78,8 @@
"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"
+ "windows": "48 8B C4 48 89 58 ? 48 89 70 ? 48 89 48 ? 55",
+ "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 ? ? ? ? 48 8D 05"
},
// "multi_manager" is passed to this
"CGameEntitySystem_FindEntityByClassName":
@@ -160,13 +160,13 @@
{
"library": "server",
"windows": "48 8B C4 4C 89 48 ? 48 89 48 ? 55 41 54",
- "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 41 89 F4 53 48 8D 35 ? ? ? ? 48 89 FB"
+ "linux": "55 48 89 E5 41 57 41 56 49 89 FE 41 55 41 54 53 48 81 EC ? ? ? ? 48 8D 05 ? ? ? ? F3 0F 11 85 ? ? ? ? 89 B5"
},
"CCSPlayer_WeaponServices_CanUse":
{
"library": "server",
"windows": "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 54 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"
+ "linux": "55 48 8D 15 ? ? ? ? 48 89 E5 41 55 41 54 49 89 F4 53 48 89 FB 48 83 EC ? 48 8B 07 48 8B 80 ? ? ? ? 48 39 D0 0F 85 ? ? ? ? 80 BF"
},
"CCSPlayer_WeaponServices_EquipWeapon":
{
@@ -198,7 +198,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 89 CD 41 54 53 48 89 D3"
+ "linux": "55 48 89 E5 41 57 41 56 41 55 41 89 CD 41 54 53 48 81 EC"
},
// 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").
@@ -222,12 +222,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"
},
- "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":
{
@@ -244,8 +238,8 @@
"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"
+ "windows": "48 89 5C 24 ? 56 48 83 EC ? 48 8B 1A",
+ "linux": "55 48 89 E5 41 56 41 55 41 54 53 48 8B 1E 48 85 DB 74"
},
// Return value of this function is used to determine whether "NETWORK_DISCONNECT_REJECT_SERVERFULL to %s: Cannot get free client\n" gets printed
"GetFreeClient":
@@ -267,7 +261,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 41 54 49 89 FC 53 48 8D 3D ? ? ? ? 48 81 EC ? ? ? ? 48 89 B5 ? ? ? ? BE ? ? ? ? F3 0F 11 85"
+ "linux": "48 B9 ? ? ? ? ? ? ? ? 55 48 89 E5 41 57 49 89 FF"
},
"TraceFunc":
{
@@ -279,8 +273,8 @@
"TraceShape":
{
"library": "server",
- "windows": "48 89 54 24 ? 48 89 4C 24 ? 55 53 56 57 41 56 41 57 48 8D AC 24 ? ? ? ? B8",
- "linux": "55 48 89 E5 41 57 49 89 CF 41 56 49 89 F6 41 55 4D 89 C5 41 54 49 89 D4"
+ "windows": "48 89 54 24 ? 48 89 4C 24 ? 55 53 56 57 41 54 41 56 41 57",
+ "linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 49 89 F7 41 56 48 8D 35 ? ? ? ? 49 89 CE"
},
"CBasePlayerPawn_GetEyePosition":
{
@@ -294,19 +288,12 @@
"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 C4 ? 48 8B BF ? ? ? ? 48 85 FF"
},
- // 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 83 EC"
+ "windows": "41 54 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 44 8B 60",
+ "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC ? 48 8B 05 ? ? ? ? 44 8B 68 ? 45 85 ED 0F 8E ? ? ? ? 8B 15"
},
// 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
@@ -328,8 +315,8 @@
"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"
+ "windows": "44 89 44 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 53 56 57 41 54 41 55 41 56 41 57 48 8B EC",
+ "linux": "55 48 89 E5 41 57 41 56 49 89 F6 41 55 41 54 49 89 CC 53 48 89 FB 48 83 EC ? 4C 8B 6F"
},
"CTriggerGravity_GravityTouch":
{
@@ -349,13 +336,13 @@
{
"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"
+ "linux": "55 31 C0 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 8D 3D ? ? ? ? 48 81 EC ? ? ? ? 89 B5"
},
// Called in return by function with "Usage: setang_exact pitch yaw " string
"CBasePlayerPawn_SnapViewAngles":
{
"library": "server",
- "windows": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B DA 48 8B F1 48 8D 55",
+ "windows": "48 89 7C 24 ? 55 48 8B EC 48 81 EC ? ? ? ? 48 8B F9 48 8D 4D ? E8 ? ? ? ? F2 0F 10 87",
"linux": "55 48 89 E5 41 57 49 89 FF 48 89 F7 41 56 41 55 41 54 53 48 81 EC ? ? ? ? E8"
},
// These two functions are called by CEnvBeam & CEnvLaser member functions, one of those functions has "env_beams cannot have the end entity be the beam itself" string
@@ -378,6 +365,13 @@
"library": "server",
"windows": "48 83 EC ? 4C 8B C2 48 8D 0D ? ? ? ? 48 8D 54 24 ? FF",
"linux": "55 48 89 F2 48 8D 35 ? ? ? ? 48 89 E5 48 83 EC"
+ },
+ // "CWorldRendererMgr::CreateWorld_Internal( %s ): Blocking load because marked for deletion during load"
+ "CWorldRendererMgr_CreateWorld_Internal":
+ {
+ "library": "worldrenderer",
+ "windows": "48 89 5C 24 ? 48 89 54 24 ? 55 56 57 48 81 EC",
+ "linux": "55 48 89 E5 41 56 41 55 41 54 49 89 FC 53 48 89 F3 48 83 EC ? F6 46"
}
},
"Offsets":
@@ -389,63 +383,63 @@
},
"CBaseEntity::SetOwner":
{
- "windows": 53,
- "linux": 52
+ "windows": 54,
+ "linux": 53
},
"CBaseEntity::Use":
{
- "windows": 145,
- "linux": 144
+ "windows": 147,
+ "linux": 146
},
"CBaseEntity::StartTouch":
{
- "windows": 148,
- "linux": 147
+ "windows": 150,
+ "linux": 149
},
"CBaseEntity::Touch":
{
- "windows": 149,
- "linux": 148
+ "windows": 151,
+ "linux": 150
},
"CBaseEntity::EndTouch":
{
- "windows": 150,
- "linux": 149
+ "windows": 152,
+ "linux": 151
},
"Teleport":
{
- "windows": 163,
- "linux": 162
+ "windows": 165,
+ "linux": 164
},
"CollisionRulesChanged":
{
- "windows": 186,
- "linux": 185
+ "windows": 188,
+ "linux": 187
},
"CCSPlayerController_Respawn":
{
- "windows": 270,
- "linux": 272
+ "windows": 274,
+ "linux": 276
},
// CBaseTrigger
"PassesTriggerFilters":
{
- "windows": 269,
- "linux": 270
+ "windows": 271,
+ "linux": 272
},
// 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": 252,
- "linux": 253
+ "windows": 255,
+ "linux": 256
},
// 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
+ // return (*(*v9 + 3096LL))(v9, v27, 0LL);
+ // 3096 (387 * 8) is the offset
"CBasePlayerPawn_CommitSuicide":
{
- "windows": 384,
- "linux": 384
+ "windows": 387,
+ "linux": 387
},
"GameEntitySystem":
{
@@ -455,15 +449,15 @@
// 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": 26,
- "linux": 27
+ "windows": 25,
+ "linux": 26
},
// 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
+ // "tried to sprint to a non-client", there will be a check above like this: if ( a2 >= *(v5 + 616) ), note that this is a CUtlVector
"CNetworkGameServer_ClientList":
{
- "windows": 73,
- "linux": 73
+ "windows": 77,
+ "linux": 77
},
// Right above "mapgroup workshop;" string there is a virtual call to this on g_pGameTypes using "workshop" string
"IGameTypes_CreateWorkshopMapGroup":
@@ -474,8 +468,8 @@
// 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": 44,
- "linux": 45
+ "windows": 45,
+ "linux": 46
},
"CCSPlayer_WeaponServices::DropWeapon":
{
@@ -490,8 +484,8 @@
// server.dll -> xref 'sv_phys_stop_at_collision' first __fastcall
"CVPhys2World::GetTouchingList":
{
- "windows": 121,
- "linux": 121
+ "windows": 122,
+ "linux": 122
}
},
"Patches":
@@ -499,7 +493,7 @@
"ServerMovementUnlock":
{
"windows": "E9 B0 00 00 00 90",
- "linux": "90 90 90 90 90 90"
+ "linux": "EB"
},
"FixWaterFloorJump":
{
diff --git a/sdk b/sdk
index e7ed969ea..625bfd4e3 160000
--- a/sdk
+++ b/sdk
@@ -1 +1 @@
-Subproject commit e7ed969ea8cb9afebd19ba6c5f262c9048890543
+Subproject commit 625bfd4e39816ad0e1eae3b3144a3b5425c5c7a0
diff --git a/src/addresses.cpp b/src/addresses.cpp
index 5fae6ed6a..9b4ce84d8 100644
--- a/src/addresses.cpp
+++ b/src/addresses.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* =============================================================================
* CS2Fixes
* Copyright (C) 2023-2026 Source2ZE
@@ -27,10 +27,10 @@
#include "tier0/memdbgon.h"
-#define RESOLVE_SIG(gameConfig, name, variable) \
- variable = (decltype(variable))gameConfig->ResolveSignature(name); \
- if (!variable) \
- return false; \
+#define RESOLVE_SIG(name, variable) \
+ variable = (decltype(variable))g_GameConfig->ResolveSignature(name); \
+ if (!variable) \
+ return false; \
Message("Found %s at 0x%p\n", name, variable);
#define RESOLVE_SF(scriptDesc, funcName, variable) \
@@ -41,7 +41,7 @@
else \
Message("Found %s::%s at 0x%p\n", scriptDesc->m_pszClassname, funcName, variable.GetPtr());
-bool addresses::Initialize(CGameConfig* g_GameConfig)
+bool addresses::Initialize()
{
modules::engine = new CModule(ROOTBIN, "engine2");
modules::tier0 = new CModule(ROOTBIN, "tier0");
@@ -51,6 +51,7 @@ bool addresses::Initialize(CGameConfig* g_GameConfig)
modules::networksystem = new CModule(ROOTBIN, "networksystem");
modules::vphysics2 = new CModule(ROOTBIN, "vphysics2");
modules::matchmaking = new CModule(GAMEBIN, "matchmaking");
+ modules::worldrenderer = new CModule(ROOTBIN, "worldrenderer");
modules::client = nullptr;
if (!CommandLine()->HasParm("-dedicated"))
@@ -62,29 +63,29 @@ bool addresses::Initialize(CGameConfig* g_GameConfig)
modules::hammer = new CModule(ROOTBIN, "tools/hammer");
#endif
- RESOLVE_SIG(g_GameConfig, "SetGroundEntity", addresses::SetGroundEntity);
- RESOLVE_SIG(g_GameConfig, "CCSPlayerController_SwitchTeam", addresses::CCSPlayerController_SwitchTeam);
- RESOLVE_SIG(g_GameConfig, "CBasePlayerController_SetPawn", addresses::CBasePlayerController_SetPawn);
- RESOLVE_SIG(g_GameConfig, "CBaseModelEntity_SetModel", addresses::CBaseModelEntity_SetModel);
- RESOLVE_SIG(g_GameConfig, "CEntitySystem_AddEntityIOEvent", addresses::CEntitySystem_AddEntityIOEvent);
- RESOLVE_SIG(g_GameConfig, "CEntityInstance_AcceptInput", addresses::CEntityInstance_AcceptInput);
- RESOLVE_SIG(g_GameConfig, "CGameEntitySystem_FindEntityByClassName", addresses::CGameEntitySystem_FindEntityByClassName);
- RESOLVE_SIG(g_GameConfig, "CGameEntitySystem_FindEntityByName", addresses::CGameEntitySystem_FindEntityByName);
- RESOLVE_SIG(g_GameConfig, "CGameRules_TerminateRound", addresses::CGameRules_TerminateRound);
- RESOLVE_SIG(g_GameConfig, "CreateEntityByName", addresses::CreateEntityByName);
- RESOLVE_SIG(g_GameConfig, "DispatchSpawn", addresses::DispatchSpawn);
- RESOLVE_SIG(g_GameConfig, "DispatchParticleEffect", addresses::DispatchParticleEffect);
- RESOLVE_SIG(g_GameConfig, "CBaseEntity_EmitSoundFilter", addresses::CBaseEntity_EmitSoundFilter);
- RESOLVE_SIG(g_GameConfig, "CBaseEntity_SetMoveType", addresses::CBaseEntity_SetMoveType);
- RESOLVE_SIG(g_GameConfig, "CTakeDamageInfo", addresses::CTakeDamageInfo_Constructor);
- RESOLVE_SIG(g_GameConfig, "CCSPlayer_WeaponServices_EquipWeapon", addresses::CCSPlayer_WeaponServices_EquipWeapon);
- RESOLVE_SIG(g_GameConfig, "GetSpawnGroups", addresses::GetSpawnGroups);
- RESOLVE_SIG(g_GameConfig, "CBasePlayerPawn_SnapViewAngles", addresses::CBasePlayerPawn_SnapViewAngles);
-
- return InitializeBanMap(g_GameConfig);
+ RESOLVE_SIG("SetGroundEntity", addresses::SetGroundEntity);
+ RESOLVE_SIG("CCSPlayerController_SwitchTeam", addresses::CCSPlayerController_SwitchTeam);
+ RESOLVE_SIG("CBasePlayerController_SetPawn", addresses::CBasePlayerController_SetPawn);
+ RESOLVE_SIG("CBaseModelEntity_SetModel", addresses::CBaseModelEntity_SetModel);
+ RESOLVE_SIG("CEntitySystem_AddEntityIOEvent", addresses::CEntitySystem_AddEntityIOEvent);
+ RESOLVE_SIG("CEntityInstance_AcceptInput", addresses::CEntityInstance_AcceptInput);
+ RESOLVE_SIG("CGameEntitySystem_FindEntityByClassName", addresses::CGameEntitySystem_FindEntityByClassName);
+ RESOLVE_SIG("CGameEntitySystem_FindEntityByName", addresses::CGameEntitySystem_FindEntityByName);
+ RESOLVE_SIG("CGameRules_TerminateRound", addresses::CGameRules_TerminateRound);
+ RESOLVE_SIG("CreateEntityByName", addresses::CreateEntityByName);
+ RESOLVE_SIG("DispatchSpawn", addresses::DispatchSpawn);
+ RESOLVE_SIG("DispatchParticleEffect", addresses::DispatchParticleEffect);
+ RESOLVE_SIG("CBaseEntity_EmitSoundFilter", addresses::CBaseEntity_EmitSoundFilter);
+ RESOLVE_SIG("CBaseEntity_SetMoveType", addresses::CBaseEntity_SetMoveType);
+ RESOLVE_SIG("CCSPlayer_WeaponServices_EquipWeapon", addresses::CCSPlayer_WeaponServices_EquipWeapon);
+ RESOLVE_SIG("GetSpawnGroups", addresses::GetSpawnGroups);
+ RESOLVE_SIG("CBasePlayerPawn_SnapViewAngles", addresses::CBasePlayerPawn_SnapViewAngles);
+ RESOLVE_SIG("CBaseEntity_TakeDamageOld", addresses::CBaseEntity_TakeDamageOld);
+
+ return InitializeBanMap();
}
-bool addresses::InitializeBanMap(CGameConfig* g_GameConfig)
+bool addresses::InitializeBanMap()
{
// This signature directly points to the instruction referencing sm_mapGcBanInformation
uintptr_t pAddr = (uintptr_t)g_GameConfig->ResolveSignature("CCSGameRules__sm_mapGcBanInformation");
diff --git a/src/addresses.h b/src/addresses.h
index d70fb3b61..a168a8b17 100644
--- a/src/addresses.h
+++ b/src/addresses.h
@@ -1,4 +1,4 @@
-/**
+/**
* =============================================================================
* CS2Fixes
* Copyright (C) 2023-2026 Source2ZE
@@ -36,6 +36,7 @@ namespace modules
inline CModule* networksystem;
inline CModule* vphysics2;
inline CModule* matchmaking;
+ inline CModule* worldrenderer;
#ifdef _WIN32
inline CModule* hammer;
#endif
@@ -59,8 +60,11 @@ class CTakeDamageInfo;
class CCSPlayer_WeaponServices;
class CBasePlayerWeapon;
class CSpawnGroupMgrGameSystem;
+struct CPulseArgumentPack;
+struct CPulseInputParamMap;
struct EmitSound_t;
struct StartSoundEventInfo;
+struct CTakeDamageResult;
// Can't be forward-declared, can't include cgamerules.h.. just define it here
struct CGcBanInformation_t
@@ -73,8 +77,8 @@ struct CGcBanInformation_t
namespace addresses
{
- bool Initialize(CGameConfig* g_GameConfig);
- bool InitializeBanMap(CGameConfig* g_GameConfig);
+ bool Initialize();
+ bool InitializeBanMap();
bool InitializeVScriptFunctions();
inline CUtlOrderedMap* sm_mapGcBanInformation;
@@ -86,7 +90,7 @@ namespace addresses
inline void(FASTCALL* UTIL_Remove)(CEntityInstance*);
inline void(FASTCALL* CEntitySystem_AddEntityIOEvent)(CEntitySystem* pEntitySystem, CEntityInstance* pTarget, const char* pszInput,
- CEntityInstance* pActivator, CEntityInstance* pCaller, variant_t* value, float flDelay, void*, void*);
+ CEntityInstance* pActivator, CEntityInstance* pCaller, variant_t* value, float flDelay, CPulseArgumentPack* pArgumentPack, CPulseInputParamMap* pParamMap);
inline void(FASTCALL* CEntityInstance_AcceptInput)(CEntityInstance* pThis, const char* pInputName,
CEntityInstance* pActivator, CEntityInstance* pCaller, variant_t* value);
@@ -102,11 +106,10 @@ namespace addresses
char iAttachmentPoint, CUtlSymbolLarge iAttachmentName, bool bResetAllParticlesOnEntity, int nSplitScreenPlayerSlot, IRecipientFilter* a7, byte* a8);
inline StartSoundEventInfo(FASTCALL* CBaseEntity_EmitSoundFilter)(IRecipientFilter& filter, CEntityIndex ent, const EmitSound_t& params);
inline void(FASTCALL* CBaseEntity_SetMoveType)(CBaseEntity* pThis, MoveType_t nMoveType, MoveCollide_t nMoveCollide);
- inline void(FASTCALL* CTakeDamageInfo_Constructor)(CTakeDamageInfo* pThis, CBaseEntity* pInflictor, CBaseEntity* pAttacker, CBaseEntity* pAbility,
- const Vector* vecDamageForce, const Vector* vecDamagePosition, float flDamage, int bitsDamageType, int iCustomDamage, void* a10);
inline void(FASTCALL* CCSPlayer_WeaponServices_EquipWeapon)(CCSPlayer_WeaponServices* pWeaponServices, CBasePlayerWeapon* pPlayerWeapon);
inline void(FASTCALL* GetSpawnGroups)(CSpawnGroupMgrGameSystem* pSpawnGroupMgr, CUtlVector* pList);
inline void(FASTCALL* CBasePlayerPawn_SnapViewAngles)(CBasePlayerPawn* pPawn, QAngle* pAngles);
+ inline int64(FASTCALL* CBaseEntity_TakeDamageOld)(CBaseEntity* pThis, CTakeDamageInfo* pInfo, CTakeDamageResult* pResult);
inline CVScriptFunction SetGravityScale;
inline CVScriptFunction ScriptSetEntityName;
diff --git a/src/buttonwatch.cpp b/src/buttonwatch.cpp
index 3f3ae9f81..d92d1968b 100644
--- a/src/buttonwatch.cpp
+++ b/src/buttonwatch.cpp
@@ -32,21 +32,11 @@
#include "entity/clogiccase.h"
#include "entity/cpointviewcontrol.h"
-CConVar g_cvarEnableButtonWatch(
- "cs2f_enable_button_watch", FCVAR_NONE, "INCOMPATIBLE WITH CS#. Whether to enable button watch or not.", false,
- [](CConVar* cvar, CSplitScreenSlot slot, const bool* new_val, const bool* old_val) {
- if (!(*new_val) || !SetupFireOutputInternalDetour())
- {
- mapIOFunctions.erase("buttonwatch");
- cvar->Set(false);
- }
- else if (!IsButtonWatchEnabled())
- mapIOFunctions["buttonwatch"] = ButtonWatch;
- });
+CConVar g_cvarEnableButtonWatch("cs2f_enable_button_watch", FCVAR_NONE, "Whether to enable button watch or not.", false);
CON_COMMAND_CHAT_FLAGS(bw, "- Toggle button watch display", ADMFLAG_GENERIC)
{
- if (!IsButtonWatchEnabled())
+ if (!g_cvarEnableButtonWatch.Get())
{
ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Button watch is disabled on this server.");
return;
@@ -84,17 +74,10 @@ CON_COMMAND_CHAT_FLAGS(bw, "- Toggle button watch display", ADMFLAG_GENERIC)
}
}
-bool IsButtonWatchEnabled()
-{
- return std::any_of(mapIOFunctions.begin(), mapIOFunctions.end(), [](const auto& p) {
- return p.first == "buttonwatch";
- });
-}
-
std::map mapRecentEnts;
-void ButtonWatch(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, const CVariant* value, float flDelay)
+void ButtonWatch(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, float flDelay)
{
- if (!IsButtonWatchEnabled() || !GetGlobals() || V_stricmp(pThis->m_pDesc->m_pName, "OnPressed") || !pActivator || !((CBaseEntity*)pActivator)->IsPawn() || !pCaller || mapRecentEnts.contains(pCaller->GetEntityIndex().Get()))
+ if (!GetGlobals() || V_stricmp(pThis->m_pDesc->m_pName, "OnPressed") || !pActivator || !((CBaseEntity*)pActivator)->IsPawn() || !pCaller || mapRecentEnts.contains(pCaller->GetEntityIndex().Get()))
return;
CCSPlayerController* ccsPlayer = CCSPlayerController::FromPawn(static_cast(pActivator));
diff --git a/src/buttonwatch.h b/src/buttonwatch.h
index 1d22e9b4c..bb72ffa26 100644
--- a/src/buttonwatch.h
+++ b/src/buttonwatch.h
@@ -20,5 +20,6 @@
#pragma once
#include "detours.h"
-bool IsButtonWatchEnabled();
-void ButtonWatch(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, const CVariant* value, float flDelay);
\ No newline at end of file
+extern CConVar g_cvarEnableButtonWatch;
+
+void ButtonWatch(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, float flDelay);
\ No newline at end of file
diff --git a/src/cdetour.h b/src/cdetour.h
deleted file mode 100644
index 2c34db3cf..000000000
--- a/src/cdetour.h
+++ /dev/null
@@ -1,153 +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 .
- */
-
-#pragma once
-#include "addresses.h"
-#include "funchook.h"
-#include "gameconfig.h"
-#include "module.h"
-#include "plat.h"
-#include "utlvector.h"
-#include
-
-class CDetourBase
-{
-public:
- virtual const char* GetName() = 0;
- virtual bool CreateDetour(CGameConfig* gameConfig) = 0;
- virtual void FreeDetour() = 0;
- virtual void EnableDetour() = 0;
- virtual void DisableDetour() = 0;
-};
-
-extern CUtlVector g_vecDetours;
-
-template
-class CDetour : public CDetourBase
-{
-public:
- CDetour(T* pfnDetour, const char* pszName);
-
- ~CDetour()
- {
- FreeDetour();
- }
-
- bool CreateDetour(CGameConfig* gameConfig) override;
- void EnableDetour();
- void DisableDetour();
- void FreeDetour() override;
- const char* GetName() override { return m_pszName; }
- T* GetFunc() { return m_pfnFunc; }
-
- // Shorthand for calling original.
- template
- auto operator()(Args&&... args)
- {
- return std::invoke(m_pfnFunc, std::forward(args)...);
- }
-
-private:
- CModule** m_pModule;
- T* m_pfnDetour;
- const char* m_pszName;
- byte* m_pSignature;
- const char* m_pSymbol;
- T* m_pfnFunc;
- funchook_t* m_hook;
- bool m_bInstalled;
-};
-
-template
-CDetour::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;
-
- g_vecDetours.AddToTail(this);
-}
-
-template
-bool CDetour::CreateDetour(CGameConfig* gameConfig)
-{
- m_pfnFunc = (T*)gameConfig->ResolveSignature(m_pszName);
- if (!m_pfnFunc)
- return false;
-
- T* pFunc = m_pfnFunc;
-
- m_hook = funchook_create();
- funchook_prepare(m_hook, (void**)&m_pfnFunc, (void*)m_pfnDetour);
-
- Message("Detoured %s at 0x%p\n", m_pszName, pFunc);
- return true;
-}
-
-template
-void CDetour::EnableDetour()
-{
- if (!m_hook)
- return;
-
- int error = funchook_install(m_hook, 0);
-
- if (!error)
- m_bInstalled = true;
- else
- Warning("funchook_install error for %s: %d %s\n", m_pszName, error, funchook_error_message(m_hook));
-}
-
-template
-void CDetour::DisableDetour()
-{
- if (!m_hook)
- return;
-
- int error = funchook_uninstall(m_hook, 0);
-
- if (!error)
- m_bInstalled = false;
- else
- Warning("funchook_uninstall error for %s: %d %s\n", m_pszName, error, funchook_error_message(m_hook));
-}
-
-template
-void CDetour::FreeDetour()
-{
- if (!m_hook)
- return;
-
- if (m_bInstalled)
- DisableDetour();
-
- int error = funchook_destroy(m_hook);
- m_hook = nullptr;
-
- if (error == 0)
- Message("Removed detour %s\n", m_pszName);
- else
- Warning("funchook_destroy error for %s: %d %s\n", m_pszName, error, funchook_error_message(m_hook));
-}
-
-#define DECLARE_DETOUR(name, detour) \
- CDetour name(detour, #name)
diff --git a/src/cfgparser.cpp b/src/cfgparser.cpp
index adfe3adf0..906e18066 100644
--- a/src/cfgparser.cpp
+++ b/src/cfgparser.cpp
@@ -24,18 +24,19 @@
CCfgParser* g_pCfgParser = nullptr;
-CON_COMMAND_F(exec_custom, " - Execute a cfg through the custom cfg parser", FCVAR_SPONLY | FCVAR_LINKED_CONCOMMAND)
+void CCfgParser::PreLevelLoad(const char* pszMapName)
{
- if (args.ArgC() < 2)
- {
- Message("Usage: exec_custom \n");
- return;
- }
-
- g_pCfgParser->ParseCfg(args[1]);
+ // Make sure convars are set before map load, currently used by map migrations
+ ExecuteConfigs(pszMapName);
}
void CCfgParser::ApplyGameSettings(const char* pszMapName)
+{
+ // Execute again for good measure, because this is when configs would normally execute
+ ExecuteConfigs(pszMapName);
+}
+
+void CCfgParser::ExecuteConfigs(const char* pszMapName)
{
// Run plugin cfg
g_pCfgParser->ParseCfg("cs2fixes/cs2fixes");
@@ -47,10 +48,9 @@ void CCfgParser::ApplyGameSettings(const char* pszMapName)
return;
// Run map cfg (if present)
- // We call ParseCfg indirectly through exec_custom, so any commands within the map cfg will be added to the command buffer after nested executes in previous configs
- char cmd[MAX_PATH];
- V_snprintf(cmd, sizeof(cmd), "exec_custom cs2fixes/maps/%s", pszMapName);
- g_pEngineServer2->ServerCommand(cmd);
+ char szCfgPath[MAX_PATH];
+ V_snprintf(szCfgPath, sizeof(szCfgPath), "cs2fixes/maps/%s", pszMapName);
+ ParseCfg(szCfgPath);
}
void CCfgParser::ParseCfg(const char* pszCfgPath)
@@ -71,10 +71,42 @@ void CCfgParser::ParseCfg(const char* pszCfgPath)
while (std::getline(cfgFile, strCommand))
{
- if (!strCommand.empty() && strCommand.back() == '\r')
- strCommand.pop_back();
+ CCommand args;
+
+ if (!args.Tokenize(strCommand.c_str()) || !args.ArgC())
+ continue;
+
+ if (!V_strcasecmp(args[0], "exec_custom"))
+ {
+ if (args.ArgC() < 2)
+ Message("Usage: exec_custom \n");
+ else
+ ParseCfg(args[1]);
+
+ continue;
+ }
+
+ ConCommandRef command(args[0], true);
+ ConVarRefAbstract convar(args[0], true);
+
+ if (command.IsValidRef())
+ {
+ CCommandContext context(CT_FIRST_SPLITSCREEN_CLIENT, -1);
+ command.Dispatch(context, args);
+ continue;
+ }
+
+ if (convar.IsValidRef())
+ {
+ // Hold on to ConVarRefAbstract's so they don't get destroyed on next iteration loop, this could cause memory issues with deferred FCVAR_PERFORMING_CALLBACKS cvar's
+ ConVarRefAbstract& cachedConvar = m_mapConVars.insert_or_assign(convar.GetAccessIndex(), convar).first->second;
+
+ if (args.ArgC() > 1 && !cachedConvar.SetString(args[1]))
+ Message("Failed to execute \"%s %s\"\n", args[0], args[1]);
+
+ continue;
+ }
- if (!strCommand.empty())
- g_pEngineServer2->ServerCommand(strCommand.c_str());
+ Message("Unknown command \"%s\"\n", args[0]);
}
}
diff --git a/src/cfgparser.h b/src/cfgparser.h
index 78433b7d7..baee9275d 100644
--- a/src/cfgparser.h
+++ b/src/cfgparser.h
@@ -19,11 +19,19 @@
#pragma once
+#include "convar.h"
+#include