From bf31cd7e62876526975fdc3c851e06477e820f69 Mon Sep 17 00:00:00 2001 From: Vauff Date: Sat, 10 Oct 2026 01:53:25 -0400 Subject: [PATCH 1/9] Fix/replace game_player_equip TriggerFor input hooks We were hooking the wrong function post 2026-09-22 CS2 update, but we don't need to rely on signatures anyways Co-authored-by: tilgep --- gamedata/cs2fixes.jsonc | 12 ------------ src/cs2_sdk/entity/cbaseentity.h | 9 +++++++++ src/detours.cpp | 23 ++++++++--------------- src/detours.h | 4 ---- src/entities.cpp | 11 +++++------ src/entities.h | 7 +++++-- 6 files changed, 27 insertions(+), 39 deletions(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 508ccd73..5eb164ae 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -229,18 +229,6 @@ "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": "48 89 5C 24 ? 48 89 74 24 ? 55 57 41 54 41 56 41 57 48 8B EC 48 83 EC ? 4C 8B F1", - "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 FC 53 48 83 EC ? E8 ? ? ? ? C7 45 ? ? ? ? ? 89 C7 66 89 45 ? 66 83 F8 ? 75 ? 48 C7 45 ? ? ? ? ? 66 83 FF ? 0F 84 ? ? ? ? 0F B7 7D ? E8 ? ? ? ? 66 89 45 ? 66 83 F8 ? 0F 84 ? ? ? ? 89 C7 E8 ? ? ? ? 0F B7 7D ? 48 89 C3 48 85 C0 74 ? 48 89 C7 E8 ? ? ? ? 48 8D 7D ? 48 89 C6 E8 ? ? ? ? 0F B7 7D ? 84 C0 0F 85 ? ? ? ? EB ? 66 0F 1F 44 00 ? E8 ? ? ? ? 48 89 C3 48 85 C0 0F 84 ? ? ? ? 48 89 C7 E8 ? ? ? ? 48 8D 7D ? 48 89 C6 E8 ? ? ? ? 84 C0 0F 84 ? ? ? ? 0F B7 7D ? 48 89 5D ? 66 83 FF" - }, - "CGamePlayerEquip_InputTriggerForActivatedPlayer": - { - "library": "server", - "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": { diff --git a/src/cs2_sdk/entity/cbaseentity.h b/src/cs2_sdk/entity/cbaseentity.h index f4685cfd..765bd168 100644 --- a/src/cs2_sdk/entity/cbaseentity.h +++ b/src/cs2_sdk/entity/cbaseentity.h @@ -34,6 +34,7 @@ class CGameUI; class CEnvHudHint; class CPointViewControl; class CBasePlayerWeapon; +class CGamePlayerEquip; class CGameSceneNode { @@ -331,6 +332,14 @@ class CBaseEntity : public CEntityInstance return nullptr; } + [[nodiscard]] CGamePlayerEquip* AsGamePlayerEquip() + { + if (V_strcasecmp(GetClassname(), "game_player_equip") == 0) + return reinterpret_cast(this); + + return nullptr; + } + /* End Custom Entities Cast */ }; diff --git a/src/detours.cpp b/src/detours.cpp index d57120c9..32410ab6 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -37,6 +37,7 @@ #include "entity/ccsplayerpawn.h" #include "entity/ccsweaponbase.h" #include "entity/cenvhudhint.h" +#include "entity/cgameplayerequip.h" #include "entity/cgamerules.h" #include "entity/cpointviewcontrol.h" #include "entity/ctakedamageinfo.h" @@ -69,8 +70,6 @@ KHOOK_MEMBER(CEntityIdentity_AcceptInput, Detour_CEntityIdentity_AcceptInput, nu KHOOK_MEMBER(CNavMesh_GetNearestNavArea, Detour_CNavMesh_GetNearestNavArea, nullptr); KHOOK_MEMBER(ProcessMovement, Detour_ProcessMovement, Detour_ProcessMovement_Post); KHOOK_MEMBER(ProcessUsercmds, Detour_ProcessUsercmds, nullptr); -KHOOK_MEMBER(CGamePlayerEquip_InputTriggerForAllPlayers, Detour_CGamePlayerEquip_InputTriggerForAllPlayers, nullptr); -KHOOK_MEMBER(CGamePlayerEquip_InputTriggerForActivatedPlayer, Detour_CGamePlayerEquip_InputTriggerForActivatedPlayer, nullptr); KHOOK_MEMBER(CTriggerGravity_GravityTouch, Detour_CTriggerGravity_GravityTouch, nullptr); KHOOK_FUNCTION(GetFreeClient, Detour_GetFreeClient, nullptr); #ifdef __linux__ @@ -532,6 +531,13 @@ KHook::Return Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, C if (!V_strcasecmp(pInputName->String(), "DisableCameraAll")) return {KHook::Action::Supersede, CPointViewControlHandler::OnDisableAll(pViewControl)}; } + else if (const auto pGamePlayerEquip = reinterpret_cast(pThis->m_pInstance)->AsGamePlayerEquip()) + { + if (!V_strcasecmp(pInputName->String(), "TriggerForActivatedPlayer") && !CGamePlayerEquipHandler::TriggerForActivatedPlayer(pGamePlayerEquip, reinterpret_cast(pActivator), value)) + return {KHook::Action::Supersede, true}; + if (!V_strcasecmp(pInputName->String(), "TriggerForAllPlayers")) + CGamePlayerEquipHandler::TriggerForAllPlayers(pGamePlayerEquip); + } if (g_pMapMigrations->Detour_CEntityIdentity_AcceptInput(pThis, pInputName, pActivator, pCaller, value)) return {KHook::Action::Supersede, true}; @@ -661,19 +667,6 @@ KHook::Return Detour_ProcessUsercmds(CCSPlayerController* pController, CU return {KHook::Action::Ignore}; } -KHook::Return Detour_CGamePlayerEquip_InputTriggerForAllPlayers(CGamePlayerEquip* pEntity, InputData_t* pInput) -{ - CGamePlayerEquipHandler::TriggerForAllPlayers(pEntity, pInput); - return {KHook::Action::Ignore}; -} -KHook::Return Detour_CGamePlayerEquip_InputTriggerForActivatedPlayer(CGamePlayerEquip* pEntity, InputData_t* pInput) -{ - if (CGamePlayerEquipHandler::TriggerForActivatedPlayer(pEntity, pInput)) - return {KHook::Action::Ignore}; - - return {KHook::Action::Supersede}; -} - KHook::Return Detour_CTriggerGravity_GravityTouch(CTriggerGravity* pEntity, CBaseEntity* pOther) { // no need to call original function here diff --git a/src/detours.h b/src/detours.h index 73f3d27c..9a1d22e4 100644 --- a/src/detours.h +++ b/src/detours.h @@ -45,8 +45,6 @@ class CServerSideClient; class INetChannel; class CBasePlayerPawn; class CUserCmd; -class CGamePlayerEquip; -class InputData_t; class CCSPlayerPawn; class CCSPlayer_UseServices; class CTraceFilter; @@ -92,8 +90,6 @@ KHook::Return Detour_CNavMesh_GetNearestNavArea(CNavMesh* pNavMesh, float KHook::Return Detour_ProcessMovement(CCSPlayer_MovementServices* pThis, void* pMove); KHook::Return Detour_ProcessMovement_Post(CCSPlayer_MovementServices* pThis, void* pMove); KHook::Return Detour_ProcessUsercmds(CCSPlayerController* pController, CUserCmd* cmds, int numcmds, bool paused, float margin); -KHook::Return Detour_CGamePlayerEquip_InputTriggerForAllPlayers(CGamePlayerEquip*, InputData_t*); -KHook::Return Detour_CGamePlayerEquip_InputTriggerForActivatedPlayer(CGamePlayerEquip*, InputData_t*); KHook::Return Detour_CTriggerGravity_GravityTouch(CTriggerGravity* pEntity, CBaseEntity* pOther); KHook::Return Detour_GetFreeClient(int64_t unk1, const __m128i* unk2, unsigned int unk3, int64_t unk4, char unk5, void* unk6); KHook::Return Detour_CCSPlayerPawn_GetMaxSpeed(CCSPlayerPawn*); diff --git a/src/entities.cpp b/src/entities.cpp index 29c67b87..3770f604 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -190,7 +190,7 @@ namespace CGamePlayerEquipHandler } } - void TriggerForAllPlayers(CGamePlayerEquip* pEntity, InputData_t* pInput) + void TriggerForAllPlayers(CGamePlayerEquip* pEntity) { const auto flags = pEntity->m_spawnflags(); @@ -214,15 +214,14 @@ namespace CGamePlayerEquipHandler } } - bool TriggerForActivatedPlayer(CGamePlayerEquip* pEntity, InputData_t* pInput) + bool TriggerForActivatedPlayer(CGamePlayerEquip* pEntity, CBaseEntity* pActivator, variant_t* value) { - const auto pCaller = pInput->pActivator; - const auto pszWeapon = ((pInput->value.m_type == FIELD_CSTRING || pInput->value.m_type == FIELD_STRING) && pInput->value.m_pszString) ? pInput->value.m_pszString : nullptr; + const auto pszWeapon = ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString) ? value->m_pszString : nullptr; - if (!pCaller || !pCaller->IsPawn()) + if (!pActivator || !pActivator->IsPawn()) return true; - const auto pPawn = reinterpret_cast(pCaller); + const auto pPawn = reinterpret_cast(pActivator); const auto flags = pEntity->m_spawnflags(); if (flags & CGamePlayerEquip::SF_PLAYEREQUIP_STRIPFIRST) diff --git a/src/entities.h b/src/entities.h index a32771e9..d18b4f6a 100644 --- a/src/entities.h +++ b/src/entities.h @@ -19,6 +19,9 @@ #pragma once +#include +#include "variant.h" + class InputData_t; class CGamePlayerEquip; class CBaseEntity; @@ -38,8 +41,8 @@ namespace CTriggerGravityHandler namespace CGamePlayerEquipHandler { void Use(CGamePlayerEquip* pEntity, InputData_t* pInput); - void TriggerForAllPlayers(CGamePlayerEquip* pEntity, InputData_t* pInput); - bool TriggerForActivatedPlayer(CGamePlayerEquip* pEntity, InputData_t* pInput); + void TriggerForAllPlayers(CGamePlayerEquip* pEntity); + bool TriggerForActivatedPlayer(CGamePlayerEquip* pEntity, CBaseEntity* pActivator, variant_t* value); void OnPrecache(CGamePlayerEquip* pEntity, const CEntityKeyValues* kv); } // namespace CGamePlayerEquipHandler From 8f6d29ca2217a5f9d73a5d1a175113774fe96a6e Mon Sep 17 00:00:00 2001 From: Vauff Date: Sat, 10 Oct 2026 19:59:29 -0400 Subject: [PATCH 2/9] Remove default hud disconnect callback Game now automatically cleans up player states on player connect (which is close enough) --- src/commands.cpp | 1 - src/cs2_sdk/entity/customhudlayout.cpp | 12 +++--------- src/cs2_sdk/entity/customhudlayout.h | 1 - 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/commands.cpp b/src/commands.cpp index 36ffad41..6210eb35 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -1219,7 +1219,6 @@ CON_COMMAND_CHAT(uitest, " () - Spawn UI panel") hLayout->SetDialogVariableString("MyLabel", "CustomText", args[2], player); hLayout->SetDisconnectCallback([](CCSCustomHudLayout* pHud, int slot) { - CCSCustomHudLayout::DefaultOnDisconnect(pHud, slot); Message("Custom disconnect callback called\n"); }); diff --git a/src/cs2_sdk/entity/customhudlayout.cpp b/src/cs2_sdk/entity/customhudlayout.cpp index 72f25a87..79991709 100644 --- a/src/cs2_sdk/entity/customhudlayout.cpp +++ b/src/cs2_sdk/entity/customhudlayout.cpp @@ -37,7 +37,6 @@ CCSCustomHudLayout* CCSCustomHudLayout::Create(std::string sLayout, std::string pKeyValues->SetString("targetname", sTargetName.c_str()); pLayout->DispatchSpawn(pKeyValues); - pLayout->SetDisconnectCallback(&DefaultOnDisconnect); return pLayout; } @@ -67,18 +66,13 @@ void CCSCustomHudLayout::OnClientDisconnect(int slot) continue; } - iterator->second.m_OnDisconnect(pLayout, slot); + if (iterator->second.m_OnDisconnect) + iterator->second.m_OnDisconnect(pLayout, slot); + iterator++; } } -void CCSCustomHudLayout::DefaultOnDisconnect(CCSCustomHudLayout* pLayout, int slot) -{ - pLayout->ClearClasses(slot); - pLayout->ClearDialogVariables(slot); - pLayout->SetInputCaptureEnabled(false, slot); -} - void CCSCustomHudLayout::OnEntityDeleted() { sm_mapCustomLayoutCallbacks.erase(GetHandle().ToInt()); diff --git a/src/cs2_sdk/entity/customhudlayout.h b/src/cs2_sdk/entity/customhudlayout.h index 1df3374d..6559a068 100644 --- a/src/cs2_sdk/entity/customhudlayout.h +++ b/src/cs2_sdk/entity/customhudlayout.h @@ -139,7 +139,6 @@ class CCSCustomHudLayout : public CBaseEntity // which clears all classes and variables for a slot, so only use this if you want custom logic void SetDisconnectCallback(CustomHudDisconnectCallback_t callback); static void OnClientDisconnect(int nSlot); - static void DefaultOnDisconnect(CCSCustomHudLayout* pLayout, int nSlot); void OnEntityDeleted(); From 1c411f75a24bd98993d03f08e5d670c7e497f3d8 Mon Sep 17 00:00:00 2001 From: Vauff Date: Wed, 14 Oct 2026 19:30:17 -0400 Subject: [PATCH 3/9] Update Windows sm_mapGcBanInformation signature --- gamedata/cs2fixes.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 5eb164ae..dc022bbf 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -288,7 +288,7 @@ "CCSGameRules__sm_mapGcBanInformation": { "library": "server", - "windows": "48 8D 0D ? ? ? ? 0F 11 44 24 ? 0F 11 44 24 ? E8", + "windows": "48 8D 0D ? ? ? ? 45 33 C0 4C 89 74 24 ? 0F 11 44 24", "linux": "48 8D 35 ? ? ? ? 89 C2 48 63 46" }, // Called right before "%d spawn groups:\n" From 9d6d4990bf69b6aaf4c219ac5e969c50b4341824 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 15 Oct 2026 03:01:01 -0400 Subject: [PATCH 4/9] Update SDK & sync build scripts (#469) * test sdk update * full pass * Clean up stale includes * fix msvc min/max bullshit for good * Update build scripts * Resolve some suppressed warnings * finish WIP fix * Remove unused offset * Switch to new range-based for loops on SDK containers * woke is dead * Match new variant_t behaviour more closely --- .gitmodules | 2 +- AMBuildScript | 339 +++++++++-------- AMBuilder | 12 +- CS2Fixes.vcxproj | 16 +- CS2Fixes.vcxproj.filters | 16 +- PackageScript | 2 +- gamedata/cs2fixes.jsonc | 5 - hl2sdk-manifests | 2 +- plugin-metadata.json | 2 +- sdk | 2 +- src/addresses.cpp | 2 +- src/addresses.h | 7 +- src/adminsystem.cpp | 53 ++- src/adminsystem.h | 1 + src/buttonwatch.cpp | 7 - src/buttonwatch.h | 1 + src/cfgparser.h | 2 +- src/commands.cpp | 27 +- src/commands.h | 2 +- src/common.h | 13 +- src/cs2_sdk/cchecktransmitinfo.h | 30 -- src/cs2_sdk/clientframe.h | 55 --- src/cs2_sdk/entity/cbaseentity.h | 4 +- src/cs2_sdk/entity/cbaseplayerpawn.h | 4 +- src/cs2_sdk/entity/ccsplayercontroller.h | 2 +- src/cs2_sdk/entity/ctakedamageinfo.h | 48 +-- src/cs2_sdk/entity/customhudlayout.h | 1 - src/cs2_sdk/entity/globaltypes.h | 74 +--- src/cs2_sdk/entity/services.h | 7 +- src/cs2_sdk/entityio.h | 44 +-- src/cs2_sdk/map.h | 2 +- src/cs2_sdk/netmessages.h | 83 ----- src/cs2_sdk/schema.cpp | 2 +- src/cs2_sdk/schema.h | 17 +- src/cs2_sdk/serversideclient.h | 451 ----------------------- src/cs2fixes.cpp | 14 +- src/cs2fixes.h | 9 +- src/ctimer.h | 1 + src/customio.h | 8 +- src/cvars.cpp | 2 +- src/cvarwhitelist.h | 2 +- src/detours.cpp | 46 +-- src/detours.h | 4 +- src/discord.cpp | 3 +- src/entities.cpp | 9 +- src/entities.h | 2 +- src/entitylistener.cpp | 2 - src/entitylistener.h | 4 +- src/entwatch.cpp | 21 +- src/eventlistener.h | 1 - src/events.cpp | 4 +- src/gamesystem.cpp | 9 +- src/gamesystem.h | 22 +- src/idlemanager.cpp | 1 + src/idlemanager.h | 2 +- src/leader.cpp | 14 +- src/map_votes.cpp | 20 +- src/map_votes.h | 10 +- src/mapmigrations.cpp | 12 +- src/mapmigrations.h | 4 +- src/mempatch.cpp | 3 +- src/panoramavote.cpp | 11 +- src/panoramavote.h | 14 +- src/patches.cpp | 8 +- src/patches.h | 1 - src/playermanager.cpp | 39 +- src/playermanager.h | 8 +- src/recipientfilters.h | 2 +- src/topdefender.cpp | 3 +- src/user_preferences.cpp | 2 +- src/user_preferences.h | 10 +- src/utils/entity.h | 4 +- src/utils/hud_manager.cpp | 2 +- src/utils/khook_helpers.h | 1 + src/utils/module.h | 2 +- src/utils/plat_unix.cpp | 5 +- src/utils/utils.cpp | 1 + src/utils/utils.h | 2 +- src/utils/vscript_function.cpp | 3 +- src/virtual_hooks.cpp | 29 +- src/virtual_hooks.h | 12 +- src/votemanager.cpp | 4 +- src/zombiereborn.cpp | 25 +- src/zombiereborn.h | 2 +- 84 files changed, 450 insertions(+), 1306 deletions(-) delete mode 100644 src/cs2_sdk/cchecktransmitinfo.h delete mode 100644 src/cs2_sdk/clientframe.h delete mode 100644 src/cs2_sdk/netmessages.h delete mode 100644 src/cs2_sdk/serversideclient.h diff --git a/.gitmodules b/.gitmodules index 096b58f9..e7195329 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "sdk"] path = sdk - url = https://github.com/alliedmodders/hl2sdk.git + url = https://github.com/alliedmodders/s2sdk.git branch = cs2 [submodule "hl2sdk-manifests"] path = hl2sdk-manifests diff --git a/AMBuildScript b/AMBuildScript index eb9bcac7..1801065b 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -1,6 +1,7 @@ # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: -import os, json, re, subprocess +import os, json, re, subprocess, shutil, sys from ambuild2.frontend.v2_2.cpp.builders import TargetSuffix +from ambuild2.util import ConsoleRed, ConsoleNormal # Edit the functions below for the extra functionality, the return should be # a list of path's to wanted locations @@ -23,6 +24,12 @@ def additionalIncludes(context, binary, sdk): # 'D:/absolute/path/to/include/folder/' ] +def hasLLDLinker(): + result = shutil.which('lld') + if not result: + result = shutil.which('ld.lld') + return result != None + def getGitHeadPath(): curr_source = builder.currentSourcePath direct_head = os.path.join(curr_source, '.git', 'HEAD') @@ -47,7 +54,7 @@ def runAndReturn(argv): output, ignored = p.communicate() rval = p.poll() if rval: - raise subprocess.CalledProcessError(rval, argv) + return None text = output.decode('utf8') return text.strip() @@ -77,8 +84,6 @@ def resolveMMSRoot(): prenormalized_path = resolveEnvPath('MMSOURCE_DEV', 'metamod-source') if not prenormalized_path: prenormalized_path = resolveEnvPath('MMSOURCE_DEV', 'mmsource-central') - if not prenormalized_path: # Legacy fallback to avoid breakages, even though 1.12 is not supported, many old dev setups are likely using this env variable - prenormalized_path = resolveEnvPath('MMSOURCE112', 'mmsource-1.12') if not prenormalized_path or not os.path.isdir(prenormalized_path): raise Exception('Could not find a source copy of Metamod:Source') @@ -108,7 +113,7 @@ class MMSPluginConfig(object): self.sdk_manifests = [] self.sdks = {} self.sdk_targets = [] - self.binaries = [] + self.tasks = [] self.mms_root = mms_root self.version_header_deps = [] self.versionlib_deps = dict() @@ -116,15 +121,15 @@ class MMSPluginConfig(object): self.target_archs = set() self.metadata = { - 'name': 'cs2fixes', - 'alias': 'cs2fixes', - 'display_name': 'CS2Fixes', - 'description': 'A Metamod plugin with fixes and features aimed but not limited to zombie escape', - 'author': 'xen, Poggu, Vauff, Ice, lonefang, Kxnrl, tilgep, EasterLee and various contributors', - 'url': 'https://github.com/Source2ZE/CS2Fixes', - 'log_tag': 'CS2Fixes', - 'license': 'GPL v3 License', - 'version': '{{parsed-version}}', + 'name': 'sample_mm', + 'alias': 'sample', + 'display_name': 'Sample Plugin', + 'description': 'Sample basic plugin', + 'author': 'AlliedModders LLC', + 'url': 'http://www.sourcemm.net/', + 'log_tag': 'SAMPLE', + 'license': 'Public Domain', + 'version': '1.0.0.{{git-shorthash}}', } if builder.options.targets: @@ -167,10 +172,6 @@ class MMSPluginConfig(object): self.sdks = SdkHelpers.sdks self.sdk_manifests = SdkHelpers.sdk_manifests self.sdk_targets = SdkHelpers.sdk_targets - - for sdk_target in self.sdk_targets: - if not sdk_target.sdk['source2']: - raise Exception('Only Source2 games are supported by this script.') def addVersioning(self, cxx): cxx.includes += [ @@ -209,6 +210,9 @@ class MMSPluginConfig(object): #define PLUGIN_LICENSE \"{self.metadata['license']}\" extern const char* PLUGIN_FULL_VERSION; +extern const char* PLUGIN_REVISION_SHORT; +extern const char* PLUGIN_REVISION_LONG; +extern const char* PLUGIN_REVISION_COUNT; #endif /* _PLUGIN_METADATA_INFORMATION_H_ */ """.encode('utf-8')) @@ -220,30 +224,47 @@ extern const char* PLUGIN_FULL_VERSION; version = self.metadata['version'] direct_head, git_head_path = getGitHeadPath() - parsed_version = 'DEV-untracked' + shorthash = longhash = revision_count = '0' if direct_head and git_head_path: # Force track head changes to trigger recompilation builder.AddConfigureFile(git_head_path) builder.AddConfigureFile(direct_head) - try: - parsed_version = runAndReturn(['git', 'describe', '--tags', '--long']) - except subprocess.SubprocessError as e: - print("git describe failed to find any tags") - try: - parsed_version = runAndReturn(['git', 'log', '--pretty=format:%h:%H', '-n', '1']) - parsed_version = parsed_version.split(':')[0] - except subprocess.SubprocessError as e: - print("git log failed to find any commit hash, falling back to placeholder version") + tag = runAndReturn(['git', 'describe', '--tags']) or 'MISSING_TAG' + commits_after_tag = '0' + + tag_match = re.match(r'(.+?)\-(\d+)\-g[a-f\d]+$', tag, re.MULTILINE) + if tag_match is not None: + tag = tag_match.group(1) + commits_after_tag = tag_match.group(2) + + revision_count = runAndReturn(['git', 'rev-list', '--count', 'HEAD']) or 'MISSING_COUNT' + revision_hash = runAndReturn(['git', 'log', '--pretty=format:%h:%H', '-n', '1']) or 'MISSING_SHORTHASH:MISSING_LONGHASH' + shorthash, longhash = revision_hash.split(':') + + if '{{git-shorthash}}' in version: + version = version.replace('{{git-shorthash}}', shorthash) + + if '{{git-longhash}}' in version: + version = version.replace('{{git-longhash}}', longhash) + + if '{{git-count}}' in version: + version = version.replace('{{git-count}}', revision_count) + + if '{{git-tag}}' in version: + version = version.replace('{{git-tag}}', tag) - if '{{parsed-version}}' in version: - version = version.replace('{{parsed-version}}', parsed_version) + if '{{git-commits-after-tag}}' in version: + version = version.replace('{{git-commits-after-tag}}', commits_after_tag) # For the version strings and git hashes compile that to a static library instead, # to prevent a full recompilation on version/git changes which would only trigger this cpp # and linking to be performed versionlib_cpp = builder.AddOutputFile(os.path.join('versioning', 'versionlib.cpp'), f""" const char *PLUGIN_FULL_VERSION = \"{version}\"; +const char *PLUGIN_REVISION_SHORT = \"{shorthash}\"; +const char *PLUGIN_REVISION_LONG = \"{longhash}\"; +const char *PLUGIN_REVISION_COUNT = \"{revision_count}\"; """.encode('utf-8')) for cxx in self.all_targets: @@ -290,155 +311,152 @@ const char *PLUGIN_FULL_VERSION = \"{version}\"; def configureCXX(self, cxx): if cxx.behavior == 'gcc': - cxx.defines += [ - 'stricmp=strcasecmp', - '_stricmp=strcasecmp', - '_snprintf=snprintf', - '_vsnprintf=vsnprintf', - 'HAVE_STDINT_H', - 'GNUC', - ] - cxx.cflags += [ - '-pipe', - '-fno-strict-aliasing', - '-Wall', - '-Wno-sign-compare', - '-Wno-uninitialized', - '-Wno-unused', - '-Wno-switch', - '-msse', - '-fPIC', - ] + self.configureGCC(cxx) + elif cxx.like('msvc'): + self.configureMSVC(cxx) - cxx.cxxflags += ['-std=c++20'] - if (builder.options.asan != '1') and ((cxx.version >= 'gcc-4.0') or cxx.family == 'clang'): - cxx.cflags += ['-fvisibility=hidden'] - cxx.cxxflags += ['-fvisibility-inlines-hidden'] - cxx.cxxflags += [ - '-fno-exceptions', - '-fno-threadsafe-statics', - '-Wno-non-virtual-dtor', - '-Wno-overloaded-virtual', - '-Wno-register', - '-Wno-invalid-offsetof', - ] - if (builder.options.asan == '1'): - cxx.cxxflags += [ - '-fsanitize=address', - '-fsanitize-address-use-after-scope', - '-fno-omit-frame-pointer', - '-g', - ] - cxx.linkflags += [ - '-fsanitize=address', - '-fsanitize-address-use-after-scope', - ] - if (cxx.version >= 'gcc-4.7' or cxx.family == 'clang'): - cxx.cxxflags += ['-Wno-delete-non-virtual-dtor'] + # Platform-specifics + if cxx.target.platform == 'linux': + cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64'] if cxx.family == 'gcc': - cxx.cflags += ['-mfpmath=sse'] - if cxx.family == 'clang': - cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch'] - if cxx.version >= 'clang-3.9': - cxx.cxxflags += ['-Wno-expansion-to-defined'] - if cxx.version >= 'clang-3.6': - cxx.cxxflags += ['-Wno-inconsistent-missing-override'] - if cxx.version >= 'clang-3.4': - cxx.cxxflags += ['-Wno-deprecated-register'] - else: - cxx.cxxflags += ['-Wno-deprecated'] + cxx.linkflags += ['-static-libgcc'] + elif cxx.family == 'clang': + cxx.linkflags += ['-lgcc_eh'] + cxx.linkflags += ['-static-libstdc++'] + + if hasLLDLinker(): + # This prevents STB_GNU_UNIQUE symbols from appearing in resulting binary + # as these cause it to not unload on dlclose which metamod relies on to unload its plugins + # as a result this messes with static/global variable destruction & causes other various effects + # like server crashes on server exit + cxx.linkflags += ['-fuse-ld=lld', '-Wl,--no-gnu-unique'] - # Work around SDK warnings. - if cxx.version >= 'clang-10.0': - cxx.cflags += [ - '-Wno-implicit-int-float-conversion', - '-Wno-tautological-overlap-compare', - ] + elif cxx.target.platform == 'windows': + cxx.defines += ['WIN32', '_WINDOWS', 'NOMINMAX'] + + def configureGCC(self, cxx): + cxx.defines += [ + 'stricmp=strcasecmp', + '_stricmp=strcasecmp', + '_snprintf=snprintf', + '_vsnprintf=vsnprintf', + 'HAVE_STDINT_H', + 'GNUC', + ] - elif cxx.like('msvc'): - if builder.options.debug == '1': - cxx.cflags += ['/MTd'] - cxx.linkflags += ['/NODEFAULTLIB:libcmt'] - else: - cxx.cflags += ['/MT'] - cxx.defines += [ - '_CRT_SECURE_NO_DEPRECATE', - '_CRT_SECURE_NO_WARNINGS', - '_CRT_NONSTDC_NO_DEPRECATE', - ] - cxx.cflags += [ - '/W3', - '/Zi', - '/std:c++20', + cxx.cflags += [ + '-pipe', + '-fno-strict-aliasing', + '-Wall', + '-Werror', + '-Wno-sign-compare', + '-Wno-unused', + '-Wno-switch', + '-Wno-unknown-pragmas', + '-Wno-dangling-else', + '-msse', + '-fPIC', + ] + + cxx.cxxflags += [ + '-std=c++20', + '-Wno-non-virtual-dtor', + '-Wno-overloaded-virtual', + '-Wno-invalid-offsetof', + ] + + if builder.options.asan == '1': + cxx.cxxflags += [ + '-fsanitize=address', + '-fsanitize-address-use-after-scope', + '-fno-omit-frame-pointer', + '-g', ] - cxx.cxxflags += ['/TP'] - cxx.linkflags += [ - '/SUBSYSTEM:WINDOWS', - 'kernel32.lib', - 'user32.lib', - 'gdi32.lib', - 'winspool.lib', - 'comdlg32.lib', - 'advapi32.lib', - 'shell32.lib', - 'ole32.lib', - 'oleaut32.lib', - 'uuid.lib', - 'odbc32.lib', - 'odbccp32.lib', + '-fsanitize=address', + '-fsanitize-address-use-after-scope', + ] + else: + cxx.cflags += ['-fvisibility=hidden'] + cxx.cxxflags += ['-fvisibility-inlines-hidden'] + + # Clang only flags + if cxx.family == 'clang': + cxx.cxxflags += [ + '-Wno-implicit-exception-spec-mismatch', + '-Wno-expansion-to-defined', + '-Wno-inconsistent-missing-override' ] # Optimization if builder.options.opt == '1': cxx.defines += ['NDEBUG'] - if cxx.behavior == 'gcc': - cxx.cflags += ['-O3'] - elif cxx.behavior == 'msvc': - cxx.cflags += ['/Ox', '/Zo'] - cxx.linkflags += ['/OPT:ICF', '/OPT:REF'] - + cxx.cflags += ['-O3'] # Debugging - if builder.options.debug == '1': + elif builder.options.debug == '1': cxx.defines += ['DEBUG', '_DEBUG'] - if cxx.behavior == 'gcc': - cxx.cflags += ['-g3'] - elif cxx.behavior == 'msvc': - cxx.cflags += ['/Od', '/RTC1'] + cxx.cflags += ['-g3'] # Don't omit the frame pointer. # This needs to be after our optimization flags which could otherwise disable it. - if cxx.behavior == 'gcc': - cxx.cflags += ['-fno-omit-frame-pointer'] - elif cxx.behavior == 'msvc': - cxx.cflags += ['/Oy-'] + cxx.cflags += ['-fno-omit-frame-pointer'] - # Platform-specifics - if cxx.target.platform == 'linux': - cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64'] - if cxx.family == 'gcc': - cxx.linkflags += ['-static-libgcc'] - elif cxx.family == 'clang': - cxx.linkflags += ['-lgcc_eh'] - cxx.linkflags += ['-static-libstdc++'] - elif cxx.target.platform == 'windows': - cxx.defines += ['WIN32', '_WINDOWS'] + def configureMSVC(self, cxx): + cxx.defines += [ + '_CRT_SECURE_NO_DEPRECATE', + '_CRT_SECURE_NO_WARNINGS', + '_CRT_NONSTDC_NO_DEPRECATE', + ] + cxx.cflags += [ + '/W3', + '/Zi', + '/std:c++20', + ] + cxx.cxxflags += ['/TP'] + cxx.linkflags += [ + '/SUBSYSTEM:WINDOWS', + 'kernel32.lib', + 'user32.lib', + 'gdi32.lib', + 'winspool.lib', + 'comdlg32.lib', + 'advapi32.lib', + 'shell32.lib', + 'ole32.lib', + 'oleaut32.lib', + 'uuid.lib', + 'odbc32.lib', + 'odbccp32.lib', + ] - def Library(self, cxx, name): - binary = cxx.Library(name) - return binary + # Optimization + if builder.options.opt == '1': + cxx.defines += ['NDEBUG'] + cxx.cflags += ['/Ox', '/Zo'] + cxx.linkflags += ['/OPT:ICF', '/OPT:REF'] + + # Debugging + if builder.options.debug == '1': + cxx.defines += ['DEBUG', '_DEBUG'] + cxx.cflags += ['/Od', '/RTC1', '/MTd'] + cxx.linkflags += ['/NODEFAULTLIB:libcmt'] + else: + cxx.cflags += ['/MT'] + + # Don't omit the frame pointer. + # This needs to be after our optimization flags which could otherwise disable it. + cxx.cflags += ['/Oy-'] - def HL2Library(self, context, compiler, name, sdk): - binary = self.Library(compiler, name) - mms_core_path = os.path.join(self.mms_root, 'core') + def HL2Library(self, context, compiler, project, sdk): + binary = project.Configure(compiler, '{0}.{1}'.format(project.name, sdk['extension']), '{0} {1}'.format(sdk['name'], compiler.target.arch)) cxx = binary.compiler self.addVersioning(cxx) cxx.cxxincludes += [ os.path.join(context.currentSourcePath), - os.path.join(mms_core_path), - os.path.join(self.mms_root, 'third_party', 'khook', 'include'), + os.path.join(self.mms_root, 'core'), + os.path.join(self.mms_root, 'third_party', 'khook', 'include') ] for other_sdk in self.sdk_manifests: @@ -448,7 +466,7 @@ const char *PLUGIN_FULL_VERSION = \"{version}\"; cxx.defines += ['META_IS_SOURCE2'] binary.sources += [ os.path.join(sdk['path'], 'public', 'tier0', 'memoverride.cpp'), - os.path.join(sdk['path'], 'tier1', 'convar.cpp'), + os.path.join(sdk['path'], 'tier0_perproject', 'convar.cpp'), ] SdkHelpers.configureCxx(context, binary, sdk) @@ -461,13 +479,20 @@ const char *PLUGIN_FULL_VERSION = \"{version}\"; return binary MMSPlugin = MMSPluginConfig() -MMSPlugin.detectSDKs() MMSPlugin.configurePluginMetadata() MMSPlugin.configure() +MMSPlugin.detectSDKs() + +if os.name == 'posix' and not hasLLDLinker(): + ConsoleRed(sys.stdout) + print('[!] LLD linker not found, using systems default.') + print('[!] This might result in a binary that is not unloadable at runtime and will potentially cause issues/crashes!') + print('[!] Please do install LLD linker for better binary stability. (apt install lld)') + ConsoleNormal(sys.stdout) BuildScripts = [ 'AMBuilder', 'PackageScript', ] -builder.Build(BuildScripts, { 'MMSPlugin': MMSPlugin }) +builder.Build(BuildScripts, { 'MMSPlugin': MMSPlugin }) \ No newline at end of file diff --git a/AMBuilder b/AMBuilder index 66d4347d..6abb84fb 100644 --- a/AMBuilder +++ b/AMBuilder @@ -1,12 +1,13 @@ -# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: +# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: import os -import subprocess + +project = builder.LibraryProject(MMSPlugin.metadata["name"]) for sdk_target in MMSPlugin.sdk_targets: sdk = sdk_target.sdk cxx = sdk_target.cxx - binary = MMSPlugin.HL2Library(builder, cxx, f'{MMSPlugin.metadata["name"]}.{sdk["name"]}', sdk) + binary = MMSPlugin.HL2Library(builder, cxx, project, sdk) binary.compiler.cxxincludes += [ os.path.join(builder.sourcePath, 'src', 'cs2_sdk'), @@ -72,7 +73,7 @@ for sdk_target in MMSPlugin.sdk_targets: 'sdk/entity2/entitysystem.cpp', 'sdk/entity2/entityidentity.cpp', 'sdk/entity2/entitykeyvalues.cpp', - 'sdk/tier1/keyvalues3.cpp', + 'sdk/tier0_perproject/keyvalues3.cpp', ] protoc_builder = builder.tools.Protoc(protoc = sdk_target.protoc, sources = [ @@ -100,5 +101,4 @@ for sdk_target in MMSPlugin.sdk_targets: binary.custom = [protoc_builder] - nodes = builder.Add(binary) - MMSPlugin.binaries += [nodes] +MMSPlugin.tasks += builder.Add(project) \ No newline at end of file diff --git a/CS2Fixes.vcxproj b/CS2Fixes.vcxproj index 797abd0e..5e73c528 100644 --- a/CS2Fixes.vcxproj +++ b/CS2Fixes.vcxproj @@ -85,7 +85,7 @@ Level3 true - WIN32;_DEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NOMINMAX;_DEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h @@ -102,7 +102,7 @@ true true true - WIN32;NDEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NOMINMAX;NDEBUG;DLL1_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use pch.h @@ -119,7 +119,7 @@ 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;%(PreprocessorDefinitions) + __STDC_LIMIT_MACROS;X64BITS;WIN32;NOMINMAX;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 @@ -145,7 +145,7 @@ 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;%(PreprocessorDefinitions) + __STDC_LIMIT_MACROS;X64BITS;WIN32;NOMINMAX;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 @@ -184,7 +184,7 @@ - + @@ -217,7 +217,7 @@ - + @@ -270,7 +270,6 @@ - @@ -290,8 +289,6 @@ - - @@ -308,7 +305,6 @@ - diff --git a/CS2Fixes.vcxproj.filters b/CS2Fixes.vcxproj.filters index d03d6a9b..6f6d191c 100644 --- a/CS2Fixes.vcxproj.filters +++ b/CS2Fixes.vcxproj.filters @@ -86,7 +86,7 @@ Source Files - + Source Files\sdk @@ -125,7 +125,7 @@ Source Files - + Source Files\sdk @@ -376,12 +376,6 @@ Header Files - - Header Files\cs2_sdk - - - Header Files\cs2_sdk - Header Files @@ -406,12 +400,6 @@ Header Files\cs2_sdk\entity - - Header Files\cs2_sdk - - - Header Files\cs2_sdk - Header Files\cs2_sdk diff --git a/PackageScript b/PackageScript index b68cbc84..e69702c8 100644 --- a/PackageScript +++ b/PackageScript @@ -94,7 +94,7 @@ for sdk_target in MMSPlugin.sdk_targets: packages[sdk['name']] = SDKPackage(cxx, sdk['name']) pdb_list = [] -for task in MMSPlugin.binaries: +for task in MMSPlugin.tasks: # Determine which sdk this binary belongs to since we encode it in its name binary_filename = os.path.splitext(os.path.basename(task.binary.path))[0] sdk_name = binary_filename.split('.')[-1] diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index dc022bbf..8e6877ce 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -429,11 +429,6 @@ "windows": 387, "linux": 387 }, - "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": { diff --git a/hl2sdk-manifests b/hl2sdk-manifests index 20b3a014..ebd6e106 160000 --- a/hl2sdk-manifests +++ b/hl2sdk-manifests @@ -1 +1 @@ -Subproject commit 20b3a014264b38908c4a5d4eb263ba2c488f3dc1 +Subproject commit ebd6e1064d64c89b19afca236656640a5ac6fde8 diff --git a/plugin-metadata.json b/plugin-metadata.json index d0e24426..2e83f165 100644 --- a/plugin-metadata.json +++ b/plugin-metadata.json @@ -7,5 +7,5 @@ "url": "https://github.com/Source2ZE/CS2Fixes", "log_tag": "CS2Fixes", "license": "GPL v3 License", - "version": "{{parsed-version}}" + "version": "{{git-tag}}-{{git-commits-after-tag}}-{{git-shorthash}}" } \ No newline at end of file diff --git a/sdk b/sdk index 625bfd4e..809a2d48 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 625bfd4e39816ad0e1eae3b3144a3b5425c5c7a0 +Subproject commit 809a2d48b5e0e6cddb1678c0f0b86a8fec604241 diff --git a/src/addresses.cpp b/src/addresses.cpp index 9b4ce84d..e49c4fcd 100644 --- a/src/addresses.cpp +++ b/src/addresses.cpp @@ -22,7 +22,7 @@ #include "utils/module.h" #include "entityinstance.h" -#include "tier1/strtools.h" +#include "tier0/tier0_strtools.h" #include "vscript/ivscript.h" #include "tier0/memdbgon.h" diff --git a/src/addresses.h b/src/addresses.h index a168a8b1..6bbce1e1 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -18,12 +18,13 @@ */ #pragma once +#include "entity2/entityclass.h" +#include "entity2/variant.h" #include "platform.h" #include "stdint.h" +#include "tier0/utlmap.h" #include "utils/module.h" #include "utils/vscript_function.h" -#include "utlstring.h" -#include "variant.h" namespace modules { @@ -87,7 +88,7 @@ namespace addresses 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* pszModel); - inline void(FASTCALL* UTIL_Remove)(CEntityInstance*); + inline BASEPTR UTIL_Remove; inline void(FASTCALL* CEntitySystem_AddEntityIOEvent)(CEntitySystem* pEntitySystem, CEntityInstance* pTarget, const char* pszInput, CEntityInstance* pActivator, CEntityInstance* pCaller, variant_t* value, float flDelay, CPulseArgumentPack* pArgumentPack, CPulseInputParamMap* pParamMap); diff --git a/src/adminsystem.cpp b/src/adminsystem.cpp index 49424d5f..16a00f39 100644 --- a/src/adminsystem.cpp +++ b/src/adminsystem.cpp @@ -18,22 +18,19 @@ */ #include "adminsystem.h" -#include "KeyValues.h" #include "commands.h" -#include "ctimer.h" -#include "detours.h" #include "discord.h" +#include "engine2/ivengineserver2.h" #include "entity/cbaseentity.h" #include "entity/cgamerules.h" -#include "entity/cparticlesystem.h" #include "entwatch.h" -#include "filesystem.h" -#include "gamesystem.h" +#include "filesystem/ifilesystem.h" #include "hud_manager.h" -#include "icvar.h" #include "interfaces/interfaces.h" #include "map_votes.h" #include "playermanager.h" +#include "tier0/icvar.h" +#include "tier0/keyvalues.h" #include "utils/entity.h" #include "votemanager.h" #include @@ -118,14 +115,12 @@ CON_COMMAND_CHAT_FLAGS(debugclientlist, "- Debug client list", ADMFLAG_ROOT) return; } - for (int i = 0; i < GetClientList()->Count(); i++) + for (CServerSideClient* pClient : *GetClientList()) { - CServerSideClient* pClient = (*GetClientList())[i]; - if (!pClient) continue; - ClientPrint(player, HUD_PRINTCONSOLE, "slot: %i address: %s signonstate: %i spawngroups: %i name: %s", pClient->GetPlayerSlot().Get(), pClient->GetRemoteAddress()->ToString(), pClient->GetSignonState(), pClient->m_vecLoadedSpawnGroups.Count(), pClient->GetClientName()); + ClientPrint(player, HUD_PRINTCONSOLE, "slot: %i address: %s signonstate: %i spawngroups: %i name: %s", pClient->GetPlayerSlot().Get(), pClient->GetRemoteAddress()->ToString(), pClient->GetSignonState(), pClient->m_LoadedSpawnGroups.Count(), pClient->GetClientName()); } } @@ -239,7 +234,7 @@ CON_COMMAND_CHAT_FLAGS(kick, " - Kick a player", ADMFLAG_KICK) } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) @@ -270,7 +265,7 @@ CON_COMMAND_CHAT_FLAGS(slay, " - Slay a player", ADMFLAG_SLAY) } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD, nType)) @@ -300,7 +295,7 @@ CON_COMMAND_CHAT_FLAGS(slap, " [damage] - Slap a player", ADMFLAG_SLAY) } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD, nType)) @@ -361,7 +356,7 @@ CON_COMMAND_CHAT_FLAGS(goto, " - Teleport to a player", ADMFLAG_SLAY) } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_SELF | NO_MULTIPLE | NO_DEAD | NO_IMMUNITY)) return; @@ -390,7 +385,7 @@ CON_COMMAND_CHAT_FLAGS(bring, " - Bring a player", ADMFLAG_SLAY) } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_SELF | NO_DEAD, nType)) @@ -415,7 +410,7 @@ CON_COMMAND_CHAT_FLAGS(bring, " - Bring a player", ADMFLAG_SLAY) CON_COMMAND_CHAT_FLAGS(noclip, "[name] - Toggle noclip on a player", ADMFLAG_CHEATS) { int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args.ArgC() < 2 ? "@me" : args[1], iNumClients, pSlots, NO_MULTIPLE | NO_DEAD | NO_SPECTATOR)) return; @@ -515,7 +510,7 @@ CON_COMMAND_CHAT_FLAGS(entfirepawn, " [parameter] - Fire outputs a } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) @@ -546,7 +541,7 @@ CON_COMMAND_CHAT_FLAGS(entfirecontroller, " [parameter] - Fire out } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) @@ -700,7 +695,7 @@ CON_COMMAND_CHAT_FLAGS(pm, " - Private message a player. This wi } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_MULTIPLE | NO_IMMUNITY | NO_BOT, nType)) @@ -932,7 +927,7 @@ CON_COMMAND_CHAT_FLAGS(who, "- List the flags of all online players", ADMFLAG_GE CON_COMMAND_CHAT(status, " - Checks a player's active punishments. Non-admins may only check their own punishments") { int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; ZEPlayer* pTargetPlayer = nullptr; bool bIsAdmin = !player || player->GetZEPlayer()->IsAdminFlagSet(ADMFLAG_GENERIC); @@ -993,7 +988,7 @@ CON_COMMAND_CHAT_FLAGS(money, " - Set a player's amount of money" } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) @@ -1038,7 +1033,7 @@ CON_COMMAND_CHAT_FLAGS(health, " - Set a player's health", ADMFLA } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_SPECTATOR, nType)) @@ -1112,7 +1107,7 @@ CON_COMMAND_CHAT_FLAGS(strip, " - Strip all the weapons/items of a player" } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_SPECTATOR, nType)) @@ -1164,7 +1159,7 @@ CON_COMMAND_CHAT_FLAGS(give, " - Give a weapon/item to a player", } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_SPECTATOR, nType)) @@ -1197,9 +1192,9 @@ CON_COMMAND_CHAT_FLAGS(give, " - Give a weapon/item to a player", { CUtlVector>* weapons = pWeaponServices->m_hMyWeapons(); - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* weapon = (*weapons)[i].Get(); + CBasePlayerWeapon* weapon = hWeapon.Get(); if (!weapon) continue; @@ -1266,7 +1261,7 @@ CON_COMMAND_CHAT_FLAGS(setteam, " - Set a player's team", ADM } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS, nType)) @@ -1854,7 +1849,7 @@ void ParseInfraction(const CCommand& args, CCSPlayerController* pAdmin, bool bAd } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; uint64 iBlockedFlags = NO_RANDOM | NO_SELF | NO_BOT | NO_UNAUTHENTICATED; diff --git a/src/adminsystem.h b/src/adminsystem.h index 34c3f311..b6361abf 100644 --- a/src/adminsystem.h +++ b/src/adminsystem.h @@ -77,6 +77,7 @@ class CInfractionBase else m_iTimestamp = duration; } + virtual ~CInfractionBase() = default; enum EInfractionType { Ban, diff --git a/src/buttonwatch.cpp b/src/buttonwatch.cpp index d92d1968..995fcaa2 100644 --- a/src/buttonwatch.cpp +++ b/src/buttonwatch.cpp @@ -22,15 +22,8 @@ #include "commands.h" #include "cs2fixes.h" #include "ctimer.h" -#include "detours.h" -#include "entity.h" -#include "entity/cbaseplayercontroller.h" #include "entity/ccsplayercontroller.h" #include "entity/ccsplayerpawn.h" -#include "entity/cgameplayerequip.h" -#include "entity/cgamerules.h" -#include "entity/clogiccase.h" -#include "entity/cpointviewcontrol.h" CConVar g_cvarEnableButtonWatch("cs2f_enable_button_watch", FCVAR_NONE, "Whether to enable button watch or not.", false); diff --git a/src/buttonwatch.h b/src/buttonwatch.h index bb72ffa2..d22a72a0 100644 --- a/src/buttonwatch.h +++ b/src/buttonwatch.h @@ -19,6 +19,7 @@ #pragma once #include "detours.h" +#include "tier0/convar.h" extern CConVar g_cvarEnableButtonWatch; diff --git a/src/cfgparser.h b/src/cfgparser.h index baee9275..118db05e 100644 --- a/src/cfgparser.h +++ b/src/cfgparser.h @@ -19,7 +19,7 @@ #pragma once -#include "convar.h" +#include "tier0/convar.h" #include class CCfgParser diff --git a/src/commands.cpp b/src/commands.cpp index 6210eb35..7be7388d 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -21,11 +21,10 @@ #include "adminsystem.h" #include "common.h" #include "ctimer.h" -#include "detours.h" #include "discord.h" -#include "engine/igameeventsystem.h" +#include "engine2/igameeventsystem.h" +#include "engine2/ivengineserver2.h" #include "entity/cbaseentity.h" -#include "entity/cbasemodelentity.h" #include "entity/ccsplayercontroller.h" #include "entity/ccsplayerpawn.h" #include "entity/ccsweaponbase.h" @@ -40,7 +39,6 @@ #include "tier0/vprof.h" #include "usermessages.pb.h" #include "utils/entity.h" -#include "utlstring.h" #include "zombiereborn.h" #undef snprintf #include "vendor/nlohmann/json.hpp" @@ -173,9 +171,8 @@ void ParseWeaponCommand(const CCommand& args, CCSPlayerController* player) CUtlVector* weaponPurchases = pPawn->m_pActionTrackingServices->m_weaponPurchasesThisRound().m_weaponPurchases; bool found = false; - FOR_EACH_VEC(*weaponPurchases, i) + for (WeaponPurchaseCount_t& purchase : *weaponPurchases) { - WeaponPurchaseCount_t& purchase = (*weaponPurchases)[i]; if (purchase.m_nItemDefIndex == pWeaponInfo->m_iItemDefinitionIndex) { // Note ammo_grenade_limit_total is not followed here, only for checking inventory space @@ -200,9 +197,9 @@ void ParseWeaponCommand(const CCommand& args, CCSPlayerController* player) { CUtlVector>* weapons = pWeaponServices->m_hMyWeapons(); - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* weapon = (*weapons)[i].Get(); + CBasePlayerWeapon* weapon = hWeapon.Get(); if (!weapon) continue; @@ -625,7 +622,7 @@ CON_COMMAND_CHAT(spec, "[name] - Spectate another player or join spectators") int iCommandPlayer = player ? player->GetPlayerSlot() : -1; int iNumClients = 0; - int pSlot[MAXPLAYERS]; + int pSlot[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlot, NO_MULTIPLE | NO_SELF | NO_DEAD | NO_SPECTATOR | NO_IMMUNITY)) return; @@ -683,7 +680,7 @@ CON_COMMAND_CHAT(info, " - Get a player's information") } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_BOT | NO_IMMUNITY, nType)) @@ -721,7 +718,7 @@ CON_COMMAND_CHAT(showteam, " - Get a player's current team") } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_MULTIPLE | NO_IMMUNITY)) return; @@ -975,7 +972,7 @@ CON_COMMAND_CHAT(test_target, " [blocked flag] [...] - Test string targett iBlockedFlags |= NO_IMMUNITY; int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, iBlockedFlags)) return; @@ -1093,7 +1090,7 @@ CON_COMMAND_CHAT(setkills, "- Set your kills") CON_COMMAND_CHAT(setcollisiongroup, " - Set a player's collision group") { int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS)) return; @@ -1115,7 +1112,7 @@ CON_COMMAND_CHAT(setcollisiongroup, " - Set a player's collision group") CON_COMMAND_CHAT(setsolidtype, " - Set a player's solid type") { int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS)) return; @@ -1137,7 +1134,7 @@ CON_COMMAND_CHAT(setsolidtype, " - Set a player's solid type") CON_COMMAND_CHAT(setinteraction, " - Set a player's interaction flags") { int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TARGET_BLOCKS)) return; diff --git a/src/commands.h b/src/commands.h index d8ce7975..52488caa 100644 --- a/src/commands.h +++ b/src/commands.h @@ -19,9 +19,9 @@ #pragma once #include "adminsystem.h" -#include "convar.h" #include "entity/ccsplayercontroller.h" #include "leader.h" +#include "tier0/convar.h" #include class CChatCommand; diff --git a/src/common.h b/src/common.h index 1e428a42..f208d4bc 100644 --- a/src/common.h +++ b/src/common.h @@ -20,22 +20,11 @@ #pragma once #include "platform.h" +#include "shareddefs.h" #include "utils.h" #define VPROF_LEVEL 1 -#define CS_TEAM_NONE 0 -#define CS_TEAM_SPECTATOR 1 -#define CS_TEAM_T 2 -#define CS_TEAM_CT 3 - -#define HUD_PRINTNOTIFY 1 -#define HUD_PRINTCONSOLE 2 -#define HUD_PRINTTALK 3 -#define HUD_PRINTCENTER 4 - -#define MAXPLAYERS 64 - #ifdef _WIN32 #define ROOTBIN "/bin/win64/" #define GAMEBIN "/csgo/bin/win64/" diff --git a/src/cs2_sdk/cchecktransmitinfo.h b/src/cs2_sdk/cchecktransmitinfo.h deleted file mode 100644 index 1a3f472d..00000000 --- a/src/cs2_sdk/cchecktransmitinfo.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "bitvec.h" -#include "eiface.h" -#include "playerslot.h" -#include "utlvector.h" - -// https://github.com/Wend4r/sourcesdk/blob/main/public/iservernetworkable.h - -struct vis_info_t_extended -{ - uint32 m_uVisBitsBufSize; - SpawnGroupHandle_t m_SpawnGroupHandle; - CBitVec<4096> m_VisBits; -}; -COMPILE_TIME_ASSERT(sizeof(vis_info_t_extended) == 520); - -class CCheckTransmitInfoExtended -{ -public: - CBitVec* m_pTransmitEntity; // entities visible/sent to client - CBitVec* m_pTransmitNonPlayers; // non-player entities needing deletion deltas - CBitVec* m_pTransmitOutOfPVS; // entities that left PVS but still need delta update - CBitVec* m_pTransmitAlways; // entity n is always sent even if not in PVS (HLTV and Replay only) - CUtlVector m_vecTargetSlots; - vis_info_t_extended m_VisInfo; - CPlayerSlot m_nPlayerSlot; - bool m_bFullUpdate = false; -}; -COMPILE_TIME_ASSERT(sizeof(CCheckTransmitInfoExtended) == 584); \ No newline at end of file diff --git a/src/cs2_sdk/clientframe.h b/src/cs2_sdk/clientframe.h deleted file mode 100644 index 3a7df38f..00000000 --- a/src/cs2_sdk/clientframe.h +++ /dev/null @@ -1,55 +0,0 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#ifndef CLIENTFRAME_H -#define CLIENTFRAME_H -#ifdef _WIN32 - #pragma once -#endif - -#include -#include -#include - -class CFrameSnapshot; - -class CClientFrame -{ -public: - virtual ~CClientFrame(); - -public: - // State of entities this frame from the POV of the client. - int tick_count; // server tick of this snapshot - int last_entity; // highest entity index - CClientFrame* m_pNext; - - // Index of snapshot entry that stores the entities that were active and the serial numbers - // for the frame number this packed entity corresponds to - // m_pSnapshot MUST be private to force using SetSnapshot(), see reference counters - CFrameSnapshot* m_pSnapshot; - - // Used by server to indicate if the entity was in the player's pvs - CBitVec transmit_entity; // if bit n is set, entity n will be send to client - CBitVec unkBitVec2080; - CBitVec unkBitVec4128; - CBitVec unkBitVec6176; - CBitVec* transmit_always; // if bit is set, don't do PVS checks before sending (HLTV only) -}; // sizeof 8232 - -// TODO substitute CClientFrameManager with an intelligent structure (Tree, hash, cache, etc) -class CClientFrameManager -{ -public: - virtual ~CClientFrameManager(void) = default; - -public: - char pad120[120]; - CUtlMemoryPool m_ClientFramePool; - CClientFrame* m_Frames; // updates can be delta'ed from here -}; // sizeof 288 - -#endif // CLIENTFRAME_H \ No newline at end of file diff --git a/src/cs2_sdk/entity/cbaseentity.h b/src/cs2_sdk/entity/cbaseentity.h index 765bd168..7fda0b3e 100644 --- a/src/cs2_sdk/entity/cbaseentity.h +++ b/src/cs2_sdk/entity/cbaseentity.h @@ -28,7 +28,7 @@ #include "globaltypes.h" #include "mathlib/vector.h" #include "schema.h" -#include "tier1/utlstringtoken.h" +#include "tier0/utlstringtoken.h" class CGameUI; class CEnvHudHint; @@ -261,7 +261,7 @@ class CBaseEntity : public CEntityInstance void Remove() { - addresses::UTIL_Remove(this); + (this->*addresses::UTIL_Remove)(); } void SetMoveType(MoveType_t nMoveType) diff --git a/src/cs2_sdk/entity/cbaseplayerpawn.h b/src/cs2_sdk/entity/cbaseplayerpawn.h index 555537ab..cf008c9a 100644 --- a/src/cs2_sdk/entity/cbaseplayerpawn.h +++ b/src/cs2_sdk/entity/cbaseplayerpawn.h @@ -47,9 +47,9 @@ class CBasePlayerPawn : public CBaseModelEntity CUtlVector>* weapons = m_pWeaponServices()->m_hMyWeapons(); std::vector vecWeaponsToDrop; - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* pWeapon = (*weapons)[i].Get(); + CBasePlayerWeapon* pWeapon = hWeapon.Get(); if (!pWeapon) continue; diff --git a/src/cs2_sdk/entity/ccsplayercontroller.h b/src/cs2_sdk/entity/ccsplayercontroller.h index e2f3378a..9464c0e8 100644 --- a/src/cs2_sdk/entity/ccsplayercontroller.h +++ b/src/cs2_sdk/entity/ccsplayercontroller.h @@ -20,8 +20,8 @@ #pragma once #include "../playermanager.h" -#include "../serversideclient.h" #include "cbaseplayercontroller.h" +#include "engine2/serversideclient.h" #include "services.h" class CCSPlayerController : public CBasePlayerController diff --git a/src/cs2_sdk/entity/ctakedamageinfo.h b/src/cs2_sdk/entity/ctakedamageinfo.h index 644d6d65..b327b7db 100644 --- a/src/cs2_sdk/entity/ctakedamageinfo.h +++ b/src/cs2_sdk/entity/ctakedamageinfo.h @@ -20,55 +20,9 @@ #pragma once #include "ehandle.h" #include "gametrace.h" +#include "shareddefs.h" #include -enum DamageTypes_t : uint32_t -{ - DMG_GENERIC = 0, // 0x0 - DMG_CRUSH = 1 << 0, // 0x1 - DMG_BULLET = 1 << 1, // 0x2 - DMG_SLASH = 1 << 2, // 0x4 - DMG_BURN = 1 << 3, // 0x8 - DMG_VEHICLE = 1 << 4, // 0x10 - DMG_FALL = 1 << 5, // 0x20 - DMG_BLAST = 1 << 6, // 0x40 - DMG_CLUB = 1 << 7, // 0x80 - DMG_SHOCK = 1 << 8, // 0x100 - DMG_SONIC = 1 << 9, // 0x200 - DMG_ENERGYBEAM = 1 << 10, // 0x400 - DMG_BUCKSHOT = 1 << 11, // 0x800 - DMG_DROWN = 1 << 14, // 0x4000 - DMG_POISON = 1 << 15, // 0x8000 - DMG_RADIATION = 1 << 16, // 0x10000 - DMG_DROWNRECOVER = 1 << 17, // 0x20000 - DMG_ACID = 1 << 18, // 0x40000 - DMG_PHYSGUN = 1 << 20, // 0x100000 - DMG_DISSOLVE = 1 << 21, // 0x200000 - DMG_BLAST_SURFACE = 1 << 22, // 0x400000 - DMG_HEADSHOT = 1 << 23, // 0x800000 -}; - -enum TakeDamageFlags_t : uint64_t -{ - DFLAG_NONE = 0, // 0x0 - DFLAG_SUPPRESS_HEALTH_CHANGES = 1 << 0, // 0x1 - DFLAG_SUPPRESS_PHYSICS_FORCE = 1 << 1, // 0x2 - DFLAG_SUPPRESS_EFFECTS = 1 << 2, // 0x4 - DFLAG_PREVENT_DEATH = 1 << 3, // 0x8 - DFLAG_FORCE_DEATH = 1 << 4, // 0x10 - DFLAG_ALWAYS_GIB = 1 << 5, // 0x20 - DFLAG_NEVER_GIB = 1 << 6, // 0x40 - DFLAG_REMOVE_NO_RAGDOLL = 1 << 7, // 0x80 - DFLAG_SUPPRESS_DAMAGE_MODIFICATION = 1 << 8, // 0x100 - DFLAG_ALWAYS_FIRE_DAMAGE_EVENTS = 1 << 9, // 0x200 - DFLAG_RADIUS_DMG = 1 << 10, // 0x400 - DFLAG_FORCEREDUCEARMOR_DMG = 1 << 11, // 0x800 - DFLAG_SUPPRESS_INTERRUPT_FLINCH = 1 << 12, // 0x1000 - DFLAG_IGNORE_DESTRUCTIBLE_PARTS = 1 << 13, // 0x2000 - DFLAG_IGNORE_ARMOR = 1 << 14, // 0x4000 - DFLAG_SUPPRESS_UTILREMOVE = 1 << 15, // 0x8000 -}; - struct AttackerInfo_t { bool m_bNeedInit; diff --git a/src/cs2_sdk/entity/customhudlayout.h b/src/cs2_sdk/entity/customhudlayout.h index 6559a068..0c2b3f5e 100644 --- a/src/cs2_sdk/entity/customhudlayout.h +++ b/src/cs2_sdk/entity/customhudlayout.h @@ -20,7 +20,6 @@ #pragma once #include "ccsplayercontroller.h" -#include "cstrike15_usermessages.pb.h" class CCSCustomHudLayout; diff --git a/src/cs2_sdk/entity/globaltypes.h b/src/cs2_sdk/entity/globaltypes.h index 285bb478..bbd4fa79 100644 --- a/src/cs2_sdk/entity/globaltypes.h +++ b/src/cs2_sdk/entity/globaltypes.h @@ -18,7 +18,9 @@ */ #pragma once +#include "networktransmitcomponent.h" #include "schema.h" +#include "shareddefs.h" #include "soundflags.h" #include @@ -57,17 +59,6 @@ enum ParticleAttachment_t : uint32_t MAX_PATTACH_TYPES = 0x10, }; -enum ObserverMode_t : uint8_t -{ - OBS_MODE_NONE = 0x0, - OBS_MODE_FIXED = 0x1, - OBS_MODE_IN_EYE = 0x2, - OBS_MODE_CHASE = 0x3, - OBS_MODE_ROAMING = 0x4, - OBS_MODE_DIRECTED = 0x5, - NUM_OBSERVER_MODES = 0x6, -}; - typedef uint32 SoundEventGuid_t; struct SndOpEventGuid_t { @@ -85,67 +76,6 @@ struct StartSoundEventInfo #pragma pack(pop) static_assert(sizeof(StartSoundEventInfo) == 20); // Ensure alignment change works -// used with EmitSound_t -enum gender_t : uint8 -{ - GENDER_NONE = 0x0, - GENDER_MALE = 0x1, - GENDER_FEMALE = 0x2, - GENDER_NAMVET = 0x3, - GENDER_TEENGIRL = 0x4, - GENDER_BIKER = 0x5, - GENDER_MANAGER = 0x6, - GENDER_GAMBLER = 0x7, - GENDER_PRODUCER = 0x8, - GENDER_COACH = 0x9, - GENDER_MECHANIC = 0xA, - GENDER_CEDA = 0xB, - GENDER_CRAWLER = 0xC, - GENDER_UNDISTRACTABLE = 0xD, - GENDER_FALLEN = 0xE, - GENDER_RIOT_CONTROL = 0xF, - GENDER_CLOWN = 0x10, - GENDER_JIMMY = 0x11, - GENDER_HOSPITAL_PATIENT = 0x12, - GENDER_BRIDE = 0x13, - GENDER_LAST = 0x14, -}; - -struct EmitSound_t -{ - EmitSound_t() : - m_pSoundName(0), - m_vecSoundOrigin(), - m_flVolume(VOL_NORM), - m_flSoundTime(0.0f), - m_nForceGuid(0), - m_nPitch(PITCH_NORM), - m_nFlags(0) - { - } - const char* m_pSoundName; // 0x0 - Vector m_vecSoundOrigin; // 0x8 - float m_flVolume; // 0x14 - float m_flSoundTime; // 0x18 -private: - uint8_t pad_1c[0x4]; - -public: - uint32_t m_nForceGuid; // 0x20 -private: - uint8_t pad_24[0x4]; - -public: - int16_t m_nPitch; // 0x28 - uint8_t m_nFlags; // 0x2a -}; // Size: 0x2b - -class CNetworkTransmitComponent -{ -public: - DECLARE_SCHEMA_CLASS_INLINE(CNetworkTransmitComponent) -}; - class CNetworkVelocityVector { public: diff --git a/src/cs2_sdk/entity/services.h b/src/cs2_sdk/entity/services.h index 8f52b483..b4a16806 100644 --- a/src/cs2_sdk/entity/services.h +++ b/src/cs2_sdk/entity/services.h @@ -23,7 +23,6 @@ #include #include -#include extern bool g_bAwsChangingTeam; @@ -61,7 +60,7 @@ class CPlayerControllerComponent SCHEMA_FIELD(CNetworkVarChainer, __m_pChainEntity) - CCSPlayerController* GetController() { return reinterpret_cast(__m_pChainEntity().m_pEntity); } + CCSPlayerController* GetController() { return reinterpret_cast(__m_pChainEntity().GetObject()); } }; class CPlayerPawnComponent @@ -95,7 +94,7 @@ class CPlayerPawnComponent SCHEMA_FIELD(CNetworkVarChainer, __m_pChainEntity) - CCSPlayerPawn* GetPawn() { return reinterpret_cast(__m_pChainEntity().m_pEntity); } + CCSPlayerPawn* GetPawn() { return reinterpret_cast(__m_pChainEntity().GetObject()); } }; class CPlayer_MovementServices : public CPlayerPawnComponent @@ -303,7 +302,7 @@ class CPlayer_ObserverServices : public CPlayerPawnComponent public: DECLARE_SCHEMA_CLASS(CPlayer_ObserverServices) - SCHEMA_FIELD(ObserverMode_t, m_iObserverMode) + SCHEMA_FIELD(uint8, m_iObserverMode) SCHEMA_FIELD(CHandle, m_hObserverTarget) SCHEMA_FIELD(ObserverMode_t, m_iObserverLastMode) SCHEMA_FIELD(bool, m_bForcedObserverMode) diff --git a/src/cs2_sdk/entityio.h b/src/cs2_sdk/entityio.h index 6ae7189a..4bc8cbf5 100644 --- a/src/cs2_sdk/entityio.h +++ b/src/cs2_sdk/entityio.h @@ -19,47 +19,11 @@ #pragma once -// Bandaid needed for #include "string_t.h" to compile... -#ifndef NULL - #define NULL 0 -#endif +#include +#include +#include -#include -#include -#include -#include - -struct EntityIOConnectionDesc_t -{ - string_t m_targetDesc; - string_t m_targetInput; - string_t m_valueOverride; - CEntityHandle m_hTarget; - EntityIOTargetType_t m_nTargetType; - int32 m_nTimesToFire; - float m_flDelay; -}; - -struct EntityIOConnection_t : EntityIOConnectionDesc_t -{ - bool m_bMarkedForRemoval; - EntityIOConnection_t* m_pNext; -}; - -struct EntityIOOutputDesc_t -{ - const char* m_pName; - uint32 m_nFlags; - uint32 m_nOutputOffset; -}; - -class CEntityIOOutput -{ -public: - void* vtable; - EntityIOConnection_t* m_pConnections; - EntityIOOutputDesc_t* m_pDesc; -}; +class CBaseEntity; class InputData_t { diff --git a/src/cs2_sdk/map.h b/src/cs2_sdk/map.h index 74bbe3e8..929f2162 100644 --- a/src/cs2_sdk/map.h +++ b/src/cs2_sdk/map.h @@ -19,7 +19,7 @@ #pragma once -#include "utlstring.h" +#include "tier0/utlstring.h" class CSingleWorldRep { diff --git a/src/cs2_sdk/netmessages.h b/src/cs2_sdk/netmessages.h deleted file mode 100644 index 061a0b2c..00000000 --- a/src/cs2_sdk/netmessages.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef NETMESSAGES_H -#define NETMESSAGES_H - -#ifdef _WIN32 - #pragma once -#endif - -#include -#include -#include -#include -#undef min -#undef max - -class CNETMsg_Tick_t : public CNetMessagePB -{ -}; - -class CNETMsg_StringCmd_t : public CNetMessagePB -{ -}; - -class CNETMsg_SpawnGroup_LoadCompleted_t : public CNetMessagePB -{ -}; - -class CCLCMsg_ClientInfo_t : public CNetMessagePB -{ -}; - -class CCLCMsg_BaselineAck_t : public CNetMessagePB -{ -}; - -class CCLCMsg_LoadingProgress_t : public CNetMessagePB -{ -}; - -class CCLCMsg_SplitPlayerConnect_t : public CNetMessagePB -{ -}; - -class CCLCMsg_SplitPlayerDisconnect_t : public CNetMessagePB -{ -}; - -class CCLCMsg_CmdKeyValues_t : public CNetMessagePB -{ -}; - -class CCLCMsg_Move_t : public CNetMessagePB -{ -}; - -class CCLCMsg_VoiceData_t : public CNetMessagePB -{ -}; - -class CCLCMsg_RespondCvarValue_t : public CNetMessagePB -{ -}; - -class NetMessageSplitscreenUserChanged_t : public CNetMessagePB -{ -}; - -class NetMessagePacketStart_t : public CNetMessagePB -{ -}; - -class NetMessagePacketEnd_t : public CNetMessagePB -{ -}; - -class NetMessageConnectionClosed_t : public CNetMessagePB -{ -}; - -class NetMessageConnectionCrashed_t : public CNetMessagePB -{ -}; - -#endif // NETMESSAGES_H diff --git a/src/cs2_sdk/schema.cpp b/src/cs2_sdk/schema.cpp index bab07e43..1ebb504f 100644 --- a/src/cs2_sdk/schema.cpp +++ b/src/cs2_sdk/schema.cpp @@ -181,7 +181,7 @@ void EntityNetworkStateChanged(uintptr_t pEntity, uint nOffset) void ChainNetworkStateChanged(uintptr_t pNetworkVarChainer, uint nLocalOffset) { - CEntityInstance* pEntity = reinterpret_cast(pNetworkVarChainer)->m_pEntity; + CEntityInstance* pEntity = reinterpret_cast(pNetworkVarChainer)->GetObject(); if (pEntity) pEntity->NetworkStateChanged(NetworkStateChangedData(nLocalOffset, -1, reinterpret_cast(pNetworkVarChainer)->m_PathIndex)); diff --git a/src/cs2_sdk/schema.h b/src/cs2_sdk/schema.h index a25035a7..d95dbe2f 100644 --- a/src/cs2_sdk/schema.h +++ b/src/cs2_sdk/schema.h @@ -32,6 +32,8 @@ #include "../addresses.h" #include "const.h" +#include "networksystem/networkvar.h" +#include "schemasystem/schemasystem.h" #include "stdint.h" #include "tier0/dbg.h" #include "virtual.h" @@ -44,21 +46,6 @@ struct SchemaKey SchemaCollectionManipulatorFn_t manipulator = nullptr; }; -class CNetworkVarChainer -{ -public: - CEntityInstance* m_pEntity; - -private: - uint8 pad_0000[24]; - -public: - ChangeAccessorFieldPathIndex_t m_PathIndex; - -private: - uint8 pad_0024[4]; -}; - void EntityNetworkStateChanged(uintptr_t pEntity, uint nOffset); void ChainNetworkStateChanged(uintptr_t pNetworkVarChainer, uint nOffset); void NetworkVarStateChanged(uintptr_t pNetworkVar, uint32_t nOffset, uint32 nNetworkStateChangedOffset); diff --git a/src/cs2_sdk/serversideclient.h b/src/cs2_sdk/serversideclient.h deleted file mode 100644 index be76fee0..00000000 --- a/src/cs2_sdk/serversideclient.h +++ /dev/null @@ -1,451 +0,0 @@ -#ifndef SERVERSIDECLIENT_H -#define SERVERSIDECLIENT_H - -#if COMPILER_MSVC - #pragma once -#endif - -#include "clientframe.h" -#include "netmessages.h" - -#include -#include -// #include // @Wend4r: use instead. -#include "circularbuffer.h" -#include "networksystem/inetworksystem.h" -#include "threadtools.h" -#include "tier1/netadr.h" -#include -#include -#include -#include - -#include -#include -#undef min -#undef max - -class CHLTVServer; -class INetMessage; -class CNetworkGameServerBase; -class CNetworkGameServer; -class CUtlSlot; - -struct HltvReplayStats_t -{ - enum FailEnum_t - { - FAILURE_ALREADY_IN_REPLAY, - FAILURE_TOO_FREQUENT, - FAILURE_NO_FRAME, - FAILURE_NO_FRAME2, - FAILURE_CANNOT_MATCH_DELAY, - FAILURE_FRAME_NOT_READY, - NUM_FAILURES - }; - - uint nClients; - uint nStartRequests; - uint nSuccessfulStarts; - uint nStopRequests; - uint nAbortStopRequests; - uint nUserCancels; - uint nFullReplays; - uint nNetAbortReplays; - uint nFailedReplays[NUM_FAILURES]; -}; // sizeof 56 - -struct Spike_t -{ -public: - CUtlString m_szDesc; - int m_nBits; -}; // sizeof 16 - -class CNetworkStatTrace -{ -public: - CUtlVector m_Records; - int m_nMinWarningBytes; - int m_nStartBit; - int m_nCurBit; -}; // sizeof 40 - -enum CopiedLockState_t : int32 -{ - CLS_NOCOPY = 0, - CLS_UNLOCKED = 1, - CLS_LOCKED_BY_COPYING_THREAD = 2, -}; - -template -class CCopyableLock : public MUTEX -{ - typedef MUTEX BaseClass; - -public: - // ... -}; - -class CUtlSignaller_Base -{ -public: - using Delegate_t = CUtlDelegate; - - CUtlSignaller_Base(const Delegate_t& other) : - m_SlotDeletionDelegate(other) {} - CUtlSignaller_Base(Delegate_t&& other) : - m_SlotDeletionDelegate(Move(other)) {} - -private: - Delegate_t m_SlotDeletionDelegate; -}; - -class CUtlSlot -{ -public: - using MTElement_t = CUtlSignaller_Base*; - - CUtlSlot() : - m_ConnectedSignallers(0, 1) {} - -private: - CCopyableLock m_Mutex; - CUtlVector m_ConnectedSignallers; -}; - -class CServerSideClientBase : public CUtlSlot, public INetworkChannelNotify, public INetworkMessageProcessingPreFilter -{ -public: - virtual ~CServerSideClientBase() = 0; - -public: - CPlayerSlot GetPlayerSlot() const { return m_nClientSlot; } - CPlayerUserId GetUserID() const { return m_UserID; } - CEntityIndex GetEntityIndex() const { return m_nEntityIndex; } - CSteamID GetClientSteamID() const { return m_SteamID; } - const char* GetClientName() const { return m_Name; } - INetChannel* GetNetChannel() const { return m_NetChannel; } - const netadr_t* GetRemoteAddress() const { return &m_nAddr.GetAddress(); } - CNetworkGameServerBase* GetServer() const { return m_Server; } - - virtual void Connect(int socket, const char* pszName, int nUserID, INetChannel* pNetChannel, bool bFakePlayer, bool bSplitClient, int iClientPlatform) = 0; - virtual void Inactivate() = 0; - virtual void Reactivate(CPlayerSlot nSlot) = 0; - virtual void SetServer(CNetworkGameServer* pNetServer) = 0; - virtual void Reconnect() = 0; - virtual void Disconnect(ENetworkDisconnectionReason reason) = 0; - virtual bool CheckConnect() = 0; - -private: - virtual void unk_10() = 0; - -public: - virtual void SetRate(int nRate) = 0; - virtual void SetUpdateRate(float fUpdateRate) = 0; - virtual int GetRate() = 0; - - virtual void Clear() = 0; - - virtual bool ExecuteStringCommand(const CNETMsg_StringCmd_t& msg) = 0; // "false" trigger an anti spam counter to kick a client. - virtual void SendNetMessage(const CNetMessage* pData, NetChannelBufType_t bufType) = 0; - -#ifdef LINUX -private: - virtual void unk_17() = 0; -#endif - -public: - virtual void ClientPrintf(PRINTF_FORMAT_STRING const char*, ...) = 0; - - bool IsConnected() const { return m_nSignonState >= SIGNONSTATE_CONNECTED; } - bool IsInGame() const { return m_nSignonState == SIGNONSTATE_FULL; } - bool IsSpawned() const { return m_nSignonState >= SIGNONSTATE_NEW; } - bool IsActive() const { return m_nSignonState == SIGNONSTATE_FULL; } - virtual bool IsFakeClient() const { return m_bFakePlayer; } - virtual bool IsHLTV() = 0; - - // Is an actual human player or splitscreen player (not a bot and not a HLTV slot) - virtual bool IsHumanPlayer() const { return false; } - virtual bool IsHearingClient(CPlayerSlot nSlot) const { return false; } - virtual bool IsLowViolenceClient() const { return m_bLowViolence; } - - virtual bool IsSplitScreenUser() const { return m_bSplitScreenUser; } - -public: // Message Handlers - virtual bool ProcessTick(const CNETMsg_Tick_t& msg) = 0; - virtual bool ProcessStringCmd(const CNETMsg_StringCmd_t& msg) = 0; - -private: - virtual bool unk_27() = 0; - virtual bool unk_28() = 0; - -public: - virtual bool ProcessSpawnGroup_LoadCompleted(const CNETMsg_SpawnGroup_LoadCompleted_t& msg) = 0; - virtual bool ProcessClientInfo(const CCLCMsg_ClientInfo_t& msg) = 0; - virtual bool ProcessBaselineAck(const CCLCMsg_BaselineAck_t& msg) = 0; - virtual bool ProcessLoadingProgress(const CCLCMsg_LoadingProgress_t& msg) = 0; - virtual bool ProcessSplitPlayerConnect(const CCLCMsg_SplitPlayerConnect_t& msg) = 0; - virtual bool ProcessSplitPlayerDisconnect(const CCLCMsg_SplitPlayerDisconnect_t& msg) = 0; - virtual bool ProcessCmdKeyValues(const CCLCMsg_CmdKeyValues_t& msg) = 0; - -private: - virtual bool unk_36() = 0; - virtual bool unk_37() = 0; - -public: - virtual bool ProcessMove(const CCLCMsg_Move_t& msg) = 0; - virtual bool ProcessVoiceData(const CCLCMsg_VoiceData_t& msg) = 0; - virtual bool ProcessRespondCvarValue(const CCLCMsg_RespondCvarValue_t& msg) = 0; - - virtual bool ProcessPacketStart(const NetMessagePacketStart_t& msg) = 0; - virtual bool ProcessPacketEnd(const NetMessagePacketEnd_t& msg) = 0; - virtual bool ProcessConnectionClosed(const NetMessageConnectionClosed_t& msg) = 0; - virtual bool ProcessConnectionCrashed(const NetMessageConnectionCrashed_t& msg) = 0; - -public: - virtual bool ProcessChangeSplitscreenUser(const NetMessageSplitscreenUserChanged_t& msg) = 0; - -private: - virtual bool unk_47() = 0; - virtual bool unk_48() = 0; - virtual bool unk_49() = 0; - -public: - virtual void ConnectionStart(INetChannel* pNetChannel) = 0; - -private: // SpawnGroup something. - virtual void unk_51() = 0; - virtual void unk_52() = 0; - -public: - virtual void ExecuteDelayedCall(void*) = 0; - - virtual bool UpdateAcknowledgedFramecount(int tick) = 0; - void ForceFullUpdate() - { - // This seems to be wrong and crashes linux, plus I can't be bothered to check the vtable - // UpdateAcknowledgedFramecount(-1); - m_nDeltaTick = -1; - } - - virtual bool ShouldSendMessages() = 0; - virtual void UpdateSendState() = 0; - - virtual const CMsgPlayerInfo& GetPlayerInfo() const { return m_playerInfo; } - - virtual void UpdateUserSettings() = 0; - virtual void ResetUserSettings() = 0; - -private: - virtual void unk_60() = 0; - -public: - virtual void SendSignonData() = 0; - virtual void SpawnPlayer() = 0; - virtual void ActivatePlayer() = 0; - - virtual void SetName(const char* name) = 0; - virtual void SetUserCVar(const char* cvar, const char* value) = 0; - - SignonState_t GetSignonState() const { return m_nSignonState; } - - virtual void FreeBaselines() = 0; - - bool IsFullyAuthenticated(void) { return m_bFullyAuthenticated; } - void SetFullyAuthenticated(void) { m_bFullyAuthenticated = true; } - - virtual CServerSideClientBase* GetSplitScreenOwner() { return m_pAttachedTo; } - - virtual int GetNumPlayers() = 0; - - virtual void ShouldReceiveStringTableUserData() = 0; - -private: - virtual void unk_70(CPlayerSlot nSlot) = 0; - virtual void unk_71() = 0; - virtual void unk_72() = 0; - -public: - virtual int GetHltvLastSendTick() = 0; - -private: - virtual void unk_74() = 0; - virtual void unk_75() = 0; - virtual void unk_76() = 0; - -public: - virtual void Await() = 0; - - virtual void MarkToKick() = 0; - virtual void UnmarkToKick() = 0; - - virtual bool ProcessSignonStateMsg(int state) = 0; - virtual void PerformDisconnection(ENetworkDisconnectionReason reason) = 0; - -public: // INetworkMessageProcessingPreFilter - virtual bool FilterMessage(const CNetMessage* pData, INetChannel* pChannel) = 0; // "Client %d(%s) tried to send a RebroadcastSourceId msg.\n" - -public: - CUtlString m_UserIDString; // 72 - CUtlString m_Name; // 80 - CPlayerSlot m_nClientSlot; // 88 - CEntityIndex m_nEntityIndex; // 92 - CNetworkGameServerBase* m_Server; // 96 - INetChannel* m_NetChannel; // 104 - uint16 m_nConnectionTypeFlags; // 112 - bool m_bMarkedToKick; // 113 - SignonState_t m_nSignonState; // 116 - bool m_bSplitScreenUser; // 120 - bool m_bSplitAllowFastDisconnect; // 121 - int m_nSplitScreenPlayerSlot; // 124 - CServerSideClientBase* m_SplitScreenUsers[4]; // 128 - CServerSideClientBase* m_pAttachedTo; // 160 - bool m_bSplitPlayerDisconnecting; // 168 - int m_UnkVariable172; // 172 - bool m_bFakePlayer; // 176 - bool m_bSendingSnapshot; // 177 - [[maybe_unused]] char pad6[0x5]; - CPlayerUserId m_UserID = -1; // 184 - bool m_bReceivedPacket; // true, if client received a packet after the last send packet - CSteamID m_SteamID; // 187 - CSteamID m_UnkSteamID; // 195 - CSteamID m_UnkSteamID2; // 203 from auth ticket - CSteamID m_nFriendsID; // 211 - ns_address m_nAddr; // 220 - ns_address m_nAddr2; // 252 - KeyValues* m_ConVars; // 288 - bool m_bUnk0; - -private: - [[maybe_unused]] char pad273[0x28]; - -public: - bool m_bConVarsChanged; // 296 - bool m_bIsHLTV; // 298 - -private: - [[maybe_unused]] char pad29[0xB]; - -public: - uint32 m_nSendtableCRC; // 312 - uint32 m_uChallengeNumber; - int m_nSignonTick; // 320 - int m_nDeltaTick; // 324 - int m_UnkVariable3; // 328 - int m_nStringTableAckTick; // 332 - int m_UnkVariable4; // 336 - CFrameSnapshot* m_pLastSnapshot; // last send snapshot - CUtlVector m_vecLoadedSpawnGroups; // 352 - CMsgPlayerInfo m_playerInfo; // 376 - CFrameSnapshot* m_pBaseline; // 432 - int m_nBaselineUpdateTick; // 440 - CBitVec m_BaselinesSent; // 444 - int m_nBaselineUsed; // 0/1 toggling flag, singaling client what baseline to use - int m_nLoadingProgress; // 0..100 progress, only valid during loading - - // This is used when we send out a nodelta packet to put the client in a state where we wait - // until we get an ack from them on this packet. - // This is for 3 reasons: - // 1. A client requesting a nodelta packet means they're screwed so no point in deluging them with data. - // Better to send the uncompressed data at a slow rate until we hear back from them (if at all). - // 2. Since the nodelta packet deletes all client entities, we can't ever delta from a packet previous to it. - // 3. It can eat up a lot of CPU on the server to keep building nodelta packets while waiting for - // a client to get back on its feet. - int m_nForceWaitForTick = -1; - - CCircularBuffer m_UnkBuffer = {1024}; // 2504 (24 bytes) - bool m_bLowViolence = false; // true if client is in low-violence mode (L4D server needs to know) - bool m_bSomethingWithAddressType = true; // 2529 - bool m_bFullyAuthenticated = false; // 2530 - bool m_bUnk1 = false; // 2531 - int m_nUnk; - - // The datagram is written to after every frame, but only cleared - // when it is sent out to the client. overflow is tolerated. - - // Time when we should send next world state update ( datagram ) - float m_fNextMessageTime = 0.0f; - float m_fAuthenticatedTime = -1.0f; - - // Default time to wait for next message - float m_fSnapshotInterval = 0.0f; - -private: - // CSVCMsg_PacketEntities_t m_packetmsg; // 2552 - [[maybe_unused]] char pad2552[0x138]; // 2552 - -public: - CNetworkStatTrace m_Trace; // 2864 - int m_spamCommandsCount = 0; // 2904 if the value is greater than 16, the player will be kicked with reason 39 - int m_unknown = 0; // 2908 - double m_lastExecutedCommand = 0.0; // 2912 if command executed more than once per second, ++m_spamCommandCount - -private: - [[maybe_unused]] char pad2920[0x20]; // 2920 -}; - -class CServerSideClient : public CServerSideClientBase -{ -public: - virtual ~CServerSideClient() = 0; - -public: - CPlayerBitVec m_VoiceStreams; // 2952 - CPlayerBitVec m_VoiceProximity; // 2960 - CCheckTransmitInfo m_PackInfo; // 2968 - CClientFrameManager m_FrameManager; // 3568 - -private: - [[maybe_unused]] char pad3856[8]; // 3856 - -public: - float m_flLastClientCommandQuotaStart = 0.0f; // 3864 - float m_flTimeClientBecameFullyConnected = -1.0f; // 3868 - bool m_bVoiceLoopback = false; // 3872 - bool m_bUnk10 = false; // 3873 - int m_nHltvReplayDelay = 0; // 3876 - CHLTVServer* m_pHltvReplayServer; // 3880 - int m_nHltvReplayStopAt; // 3888 - int m_nHltvReplayStartAt; // 3892 - int m_nHltvReplaySlowdownBeginAt; // 3896 - int m_nHltvReplaySlowdownEndAt; // 3900 - float m_flHltvReplaySlowdownRate; // 3904 - int m_nHltvLastSendTick; // 3908 - float m_flHltvLastReplayRequestTime; // 3912 - CUtlVector m_HltvQueuedMessages; // 3920 - HltvReplayStats_t m_HltvReplayStats; // 3944 - void* m_pLastJob; // 4000 - -private: - [[maybe_unused]] char pad3984[8]; // 4008 -}; - -// not full class reversed -class CHLTVClient : public CServerSideClientBase -{ -public: - virtual ~CHLTVClient() = 0; - -public: - CNetworkGameServerBase* m_pHLTV; // 2960 - CUtlString m_szPassword; // 2968 - CUtlString m_szChatGroup; // 2976 // "all" or "group%d" - double m_fLastSendTime = 0.0; // 2984 - double m_flLastChatTime = 0.0; // 2992 - int m_nLastSendTick = 0; // 2996 - int m_unknown2 = 0; // 3000 - int m_nFullFrameTime = 0; // 3008 - int m_unknown3 = 0; // 3012 - -public: - bool m_bNoChat = false; // 3016 - bool m_bUnkBool = false; // 3017 - bool m_bUnkBool2 = false; // 3018 - bool m_bUnkBool3 = false; // 3019 - -private: - [[maybe_unused]] char pad3976[0x24]; // 3020 -}; - -#endif // SERVERSIDECLIENT_H diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 8e3290d2..31f14648 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -18,10 +18,12 @@ */ #include "cs2fixes.h" -#include "iserver.h" +#include "engine2/inetworkgameserver.h" +#include "engine2/inetworkserverservice.h" +#include "engine2/ivengineserver2.h" +#include "engine2/networkgameserverbase.h" #include "adminsystem.h" -#include "appframework/IAppSystem.h" #include "cfgparser.h" #include "commands.h" #include "common.h" @@ -38,7 +40,6 @@ #include "gameconfig.h" #include "gamesystem.h" #include "hud_manager.h" -#include "icvar.h" #include "idlemanager.h" #include "khook_helpers.h" #include "map_votes.h" @@ -48,6 +49,7 @@ #include "patches.h" #include "playermanager.h" #include "schemasystem/schemasystem.h" +#include "tier0/icvar.h" #include "user_preferences.h" #include "virtual_hooks.h" #include "votemanager.h" @@ -68,12 +70,6 @@ float g_flLastTickedTime = 0.0f; bool g_bHasTicked = false; bool g_bRequiredInitLoaded = true; -CGameEntitySystem* GameEntitySystem() -{ - static int offset = g_GameConfig->GetOffset("GameEntitySystem"); - return *reinterpret_cast((uintptr_t)(g_pGameResourceServiceServer) + offset); -} - // Will return null between map end & new map startup, null check if necessary! INetworkGameServer* GetNetworkGameServer() { diff --git a/src/cs2fixes.h b/src/cs2fixes.h index e34860e1..c39e2df5 100644 --- a/src/cs2fixes.h +++ b/src/cs2fixes.h @@ -19,16 +19,17 @@ #pragma once -#include "cs2_sdk/netmessages.h" -#include "engine/igameeventsystem.h" +#include "engine2/igameeventsystem.h" +#include "engine2/isource2engine.h" #include "entity/cgamerules.h" -#include "gamesystems/spawngroup_manager.h" #include "igameevents.h" +#include "netmessages.pb.h" +#include "networksystem/inetworkmessages.h" #include "networksystem/inetworkserializer.h" #include "public/ics2fixes.h" #include "steam/isteamhttp.h" #include -#include +#include #ifdef AMBUILD #include "version_gen.h" diff --git a/src/ctimer.h b/src/ctimer.h index e152550b..d44f3465 100644 --- a/src/ctimer.h +++ b/src/ctimer.h @@ -40,6 +40,7 @@ class CTimerBase void SetLastExecute(float flLastExecute) { m_flLastExecute = flLastExecute; } public: + virtual ~CTimerBase() = default; virtual bool Execute(bool bAutomaticExecute = false) = 0; virtual void Cancel() = 0; diff --git a/src/customio.h b/src/customio.h index d6515eb6..72136474 100644 --- a/src/customio.h +++ b/src/customio.h @@ -19,14 +19,14 @@ #pragma once -#include "convar.h" -#include "utlstring.h" +#include "shareddefs.h" +#include "tier0/convar.h" +#include "tier0/utlstring.h" class CEntityIdentity; class CEntityInstance; class CBaseEntity; class CCSPlayerPawn; -enum DamageTypes_t : unsigned int; extern CConVar g_cvarBurnParticle; @@ -40,4 +40,4 @@ bool IgnitePawn(CCSPlayerPawn* pEntity, CBaseEntity* pInflictor = nullptr, CBaseEntity* pAttacker = nullptr, CBaseEntity* pAbility = nullptr, - DamageTypes_t nDamageType = DamageTypes_t(8)); // DMG_BURN + DamageTypes_t nDamageType = DMG_BURN); diff --git a/src/cvars.cpp b/src/cvars.cpp index 89863117..718d0087 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -18,7 +18,7 @@ */ #include "common.h" -#include "icvar.h" +#include "tier0/icvar.h" #include "tier0/memdbgon.h" diff --git a/src/cvarwhitelist.h b/src/cvarwhitelist.h index ecb77a70..8310cc56 100644 --- a/src/cvarwhitelist.h +++ b/src/cvarwhitelist.h @@ -19,7 +19,7 @@ #pragma once -#include "convar.h" +#include "tier0/convar.h" #undef snprintf #include "vendor/nlohmann/json_fwd.hpp" diff --git a/src/detours.cpp b/src/detours.cpp index 32410ab6..1b292335 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -26,10 +26,10 @@ #include "buttonwatch.h" #include "commands.h" #include "common.h" -#include "ctimer.h" #include "customio.h" #include "cvarwhitelist.h" #include "detours.h" +#include "engine2/serversideclient.h" #include "entities.h" #include "entity/cbasemodelentity.h" #include "entity/cbeam.h" @@ -44,16 +44,13 @@ #include "entity/ctriggerpush.h" #include "entity/services.h" #include "entwatch.h" -#include "gameconfig.h" #include "igameevents.h" #include "irecipientfilter.h" #include "khook_helpers.h" #include "map_votes.h" #include "mapmigrations.h" -#include "module.h" -#include "networksystem/inetworkserializer.h" #include "playermanager.h" -#include "serversideclient.h" +#include "tier0/splitstring.h" #include "tier0/vprof.h" #include "votemanager.h" #include "zombiereborn.h" @@ -454,10 +451,12 @@ KHook::Return Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, C // Handle KeyValue(s) if (!V_strnicmp(pInputName->String(), "KeyValue", 8)) { - if ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString) + const char* pszValue = value->ToString(); + + if ((value->GetType() == FIELD_CSTRING || value->GetType() == FIELD_STRING) && pszValue && *pszValue) { // always const char*, even if it's FIELD_STRING (that is bug string from lua 'EntFire') - return {KHook::Action::Supersede, CustomIO_HandleInput(pThis->m_pInstance, value->m_pszString, pActivator, pCaller)}; + return {KHook::Action::Supersede, CustomIO_HandleInput(pThis->m_pInstance, pszValue, pActivator, pCaller)}; } Message("Invalid value type for input %s\n", pInputName->String()); return {KHook::Action::Supersede, false}; @@ -466,11 +465,12 @@ KHook::Return Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, C if (!V_strnicmp(pInputName->String(), "IgniteL", 7)) // Override IgniteLifetime { float flDuration = 0.f; + const char* pszValue = value->ToString(); - if ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString) - flDuration = V_StringToFloat32(value->m_pszString, 0.f); + if ((value->GetType() == FIELD_CSTRING || value->GetType() == FIELD_STRING) && pszValue && *pszValue) + flDuration = V_StringToFloat32(pszValue, 0.f); else - flDuration = value->m_float32; + flDuration = value->Get(); CCSPlayerPawn* pPawn = reinterpret_cast(pThis->m_pInstance); @@ -480,11 +480,12 @@ KHook::Return Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, C else if (!V_strnicmp(pInputName->String(), "AddScore", 8)) { int iScore = 0; + const char* pszValue = value->ToString(); - if ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString) - iScore = V_StringToInt32(value->m_pszString, 0); + if ((value->GetType() == FIELD_CSTRING || value->GetType() == FIELD_STRING) && pszValue && *pszValue) + iScore = V_StringToInt32(pszValue, 0); else - iScore = value->m_int32; + iScore = value->Get(); CCSPlayerPawn* pPawn = reinterpret_cast(pThis->m_pInstance); @@ -498,8 +499,10 @@ KHook::Return Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, C { if (const auto pHudHint = reinterpret_cast(pThis->m_pInstance)->AsHudHint()) { - if ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString) - pHudHint->m_iszMessage(GameEntitySystem()->AllocPooledString(value->m_pszString)); + const char* pszValue = value->ToString(); + + if ((value->GetType() == FIELD_CSTRING || value->GetType() == FIELD_STRING) && pszValue && *pszValue) + pHudHint->m_iszMessage(GameEntitySystem()->AllocPooledString(pszValue)); return {KHook::Action::Supersede, true}; } } @@ -507,8 +510,10 @@ KHook::Return Detour_CEntityIdentity_AcceptInput(CEntityIdentity* pThis, C { if (const auto pModelEntity = reinterpret_cast(pThis->m_pInstance)->AsBaseModelEntity()) { - if ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString && PrepareMapSetModel(pModelEntity)) - pModelEntity->SetModel(value->m_pszString); + const char* pszValue = value->ToString(); + + if ((value->GetType() == FIELD_CSTRING || value->GetType() == FIELD_STRING) && pszValue && *pszValue && PrepareMapSetModel(pModelEntity)) + pModelEntity->SetModel(pszValue); return {KHook::Action::Supersede, true}; } @@ -689,10 +694,8 @@ KHook::Return Detour_GetFreeClient(int64_t unk1, const __m12 return {KHook::Action::Ignore}; // Phantom client fix - for (int i = 0; i < GetClientList()->Count(); i++) + for (CServerSideClient* pClient : *GetClientList()) { - CServerSideClient* pClient = (*GetClientList())[i]; - if (pClient && pClient->GetSignonState() < SIGNONSTATE_CONNECTED) return {KHook::Action::Supersede, pClient}; } @@ -937,9 +940,8 @@ KHook::Return Detour_CWorldRendererMgr_CreateWorld_Internal_Po auto pWorld = singleWorld->m_pCWorld; auto vecLumpData = (CUtlVector*)((uint8_t*)pWorld + 0x298); - FOR_EACH_VEC(*vecLumpData, i) + for (auto& lump : *vecLumpData) { - auto& lump = (*vecLumpData)[i]; auto lumpData = *(LumpData**)lump; auto vecEntityKeyValues = (CUtlVector*)((uint8_t*)lumpData + 0x1220); diff --git a/src/detours.h b/src/detours.h index 9a1d22e4..dda7d4a3 100644 --- a/src/detours.h +++ b/src/detours.h @@ -21,7 +21,7 @@ #include "cs2_sdk/entityio.h" #include "khook.hpp" #include "map.h" -#include +#include class CCheckTransmitInfo; class IRecipientFilter; @@ -55,6 +55,8 @@ class QAngle; class CEconItemView; class CCSGameRules; class CBeam; +class IWorldRendererMgr; +struct CPulseArgumentPack; struct CTakeDamageResult; enum class AcquireMethod diff --git a/src/discord.cpp b/src/discord.cpp index cad81a75..c5b2f3f7 100644 --- a/src/discord.cpp +++ b/src/discord.cpp @@ -18,11 +18,10 @@ */ #include "discord.h" -#include "KeyValues.h" #include "common.h" #include "httpmanager.h" #include "interfaces/interfaces.h" -#include "utlstring.h" +#include "tier0/keyvalues.h" #include #include "vendor/nlohmann/json.hpp" diff --git a/src/entities.cpp b/src/entities.cpp index 3770f604..e23385bf 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -21,7 +21,6 @@ #include "ctimer.h" #include "entity.h" -#include "entity/cbaseplayercontroller.h" #include "entity/ccsplayercontroller.h" #include "entity/ccsplayerpawn.h" #include "entity/cgameplayerequip.h" @@ -67,9 +66,9 @@ static void StripPlayer(CCSPlayerPawn* pPawn, const std::unordered_set CUtlVector>* weapons = pWeaponService->m_hMyWeapons(); std::vector vecWeaponsToRemove; - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* weapon = (*weapons)[i].Get(); + CBasePlayerWeapon* weapon = hWeapon.Get(); if (!weapon) continue; @@ -216,7 +215,7 @@ namespace CGamePlayerEquipHandler bool TriggerForActivatedPlayer(CGamePlayerEquip* pEntity, CBaseEntity* pActivator, variant_t* value) { - const auto pszWeapon = ((value->m_type == FIELD_CSTRING || value->m_type == FIELD_STRING) && value->m_pszString) ? value->m_pszString : nullptr; + const auto pszWeapon = (value->GetType() == FIELD_CSTRING || value->GetType() == FIELD_STRING) ? value->ToString() : nullptr; if (!pActivator || !pActivator->IsPawn()) return true; @@ -241,7 +240,7 @@ namespace CGamePlayerEquipHandler if (!pItemServices) return true; - if (pszWeapon && V_strcmp(pszWeapon, "(null)")) + if (pszWeapon && *pszWeapon && V_strcmp(pszWeapon, "(null)")) { pItemServices->GiveNamedItemAws(pszWeapon); // Don't execute game function (we fixed string param) diff --git a/src/entities.h b/src/entities.h index d18b4f6a..a878e7a3 100644 --- a/src/entities.h +++ b/src/entities.h @@ -19,8 +19,8 @@ #pragma once +#include "entity2/variant.h" #include -#include "variant.h" class InputData_t; class CGamePlayerEquip; diff --git a/src/entitylistener.cpp b/src/entitylistener.cpp index ab5d84a0..60696fc1 100644 --- a/src/entitylistener.cpp +++ b/src/entitylistener.cpp @@ -26,8 +26,6 @@ #include "entity/cgamerules.h" #include "entityclass.h" #include "entwatch.h" -#include "gameconfig.h" -#include "plat.h" CEntityListener* g_pEntityListener = nullptr; diff --git a/src/entitylistener.h b/src/entitylistener.h index bcab8be9..106a5101 100644 --- a/src/entitylistener.h +++ b/src/entitylistener.h @@ -18,9 +18,9 @@ */ #pragma once -#include "entitysystem.h" +#include "gameentitysystem.h" -class CEntityListener : public IEntityListener +class CEntityListener final : public IEntityListener { void OnEntitySpawned(CEntityInstance* pEntity) override; void OnEntityCreated(CEntityInstance* pEntity) override; diff --git a/src/entwatch.cpp b/src/entwatch.cpp index 3c77ee84..916b3710 100644 --- a/src/entwatch.cpp +++ b/src/entwatch.cpp @@ -21,33 +21,22 @@ #include "commands.h" #include "cs2fixes.h" #include "ctimer.h" -#include "customio.h" #include "detours.h" -#include "engine/igameeventsystem.h" #include "entity/cbasebutton.h" #include "entity/ccsplayercontroller.h" #include "entity/ccsplayerpawn.h" -#include "entity/cgamerules.h" #include "entity/cmathcounter.h" #include "entity/cpointworldtext.h" -#include "entity/cteam.h" #include "entity/services.h" #include "eventlistener.h" -#include "gameevents.pb.h" #include "leader.h" #include "map_votes.h" -#include "networksystem/inetworkmessages.h" #include "playermanager.h" -#include "recipientfilters.h" -#include "serversideclient.h" -#include "tier0/vprof.h" #include "user_preferences.h" -#include "usermessages.pb.h" #include "utils/entity.h" #include "vendor/nlohmann/json.hpp" #include "zombiereborn.h" #include -#include #include "tier0/memdbgon.h" @@ -1696,9 +1685,9 @@ void CEWHandler::Transfer(CCSPlayerController* pCaller, int iItemInstance, CHand } CUtlVector>* weapons = pOwnerPawn->m_pWeaponServices()->m_hMyWeapons(); - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* pWeapon = (*weapons)[i].Get(); + CBasePlayerWeapon* pWeapon = hWeapon.Get(); if (!pWeapon) continue; @@ -1713,9 +1702,9 @@ void CEWHandler::Transfer(CCSPlayerController* pCaller, int iItemInstance, CHand // Make receiver drop the weapon in the item slot CUtlVector>* weapons = pReceiverPawn->m_pWeaponServices()->m_hMyWeapons(); - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* pWeapon = (*weapons)[i].Get(); + CBasePlayerWeapon* pWeapon = hWeapon.Get(); if (!pWeapon) continue; @@ -2365,7 +2354,7 @@ CON_COMMAND_CHAT_FLAGS(etransfer, " - Transfer an En } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; // Find receiver if (!g_playerManager->CanTargetPlayers(player, args[2], iNumClients, pSlots, NO_MULTIPLE | NO_SPECTATOR | NO_DEAD)) diff --git a/src/eventlistener.h b/src/eventlistener.h index 0c482b8d..f5cc1cd4 100644 --- a/src/eventlistener.h +++ b/src/eventlistener.h @@ -20,7 +20,6 @@ #pragma once #include "common.h" #include "igameevents.h" -#include "utlstring.h" class CGameEventListener; diff --git a/src/events.cpp b/src/events.cpp index a945929c..e64cec2c 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -17,12 +17,11 @@ * this program. If not, see . */ -#include "KeyValues.h" #include "commands.h" #include "common.h" #include "ctimer.h" +#include "engine2/ivengineserver2.h" #include "entities.h" -#include "entity/cbaseplayercontroller.h" #include "entity/cgamerules.h" #include "entwatch.h" #include "eventlistener.h" @@ -32,7 +31,6 @@ #include "map_votes.h" #include "mapmigrations.h" #include "panoramavote.h" -#include "recipientfilters.h" #include "topdefender.h" #include "votemanager.h" #include "zombiereborn.h" diff --git a/src/gamesystem.cpp b/src/gamesystem.cpp index ed00ec15..1214f0cd 100644 --- a/src/gamesystem.cpp +++ b/src/gamesystem.cpp @@ -19,7 +19,6 @@ #include "gamesystem.h" #include "addresses.h" -#include "adminsystem.h" #include "common.h" #include "customio.h" #include "entities.h" @@ -201,13 +200,11 @@ GS_EVENT_MEMBER(CGameSystem, PostSpawnGroupLoad) // Ensure clients have no leaked spawngroups every time a new one loads // Due to a timing problem for leaked spawngroups with this callback, clients may have one lingering, this is fine since it'll still be taken care of next time a spawngroup loads - FOR_EACH_VEC(*pClients, i) + for (auto pClient : *pClients) { - auto pClient = (*pClients)[i]; - - if (!pClient || pClient->m_vecLoadedSpawnGroups.Count() == vecActualSpawnGroups.Count()) + if (!pClient || pClient->m_LoadedSpawnGroups.Count() == vecActualSpawnGroups.Count()) continue; - pClient->m_vecLoadedSpawnGroups = vecActualSpawnGroups; + pClient->m_LoadedSpawnGroups = vecActualSpawnGroups; } } \ No newline at end of file diff --git a/src/gamesystem.h b/src/gamesystem.h index 2d2d7352..e59b5064 100644 --- a/src/gamesystem.h +++ b/src/gamesystem.h @@ -32,7 +32,7 @@ bool InitGameSystems(); bool UnregisterGameSystem(); template -class CGameSystemStaticCustomFactory : public CGameSystemStaticFactory +class CGameSystemStaticCustomFactory final : public CGameSystemStaticFactory { public: CGameSystemStaticCustomFactory(const char* pName, T* pActualGlobal, U** ppGlobalPointer = nullptr) : @@ -52,7 +52,7 @@ class CGameSystemStaticCustomFactory : public CGameSystemStaticFactory *CBaseGameSystemFactory::sm_pFirst = pFactoryCurrent->m_pNext; else pFactoryPrevious->m_pNext = pFactoryCurrent->m_pNext; - delete pFactoryCurrent; + delete this; return; } pFactoryPrevious = pFactoryCurrent; @@ -93,24 +93,6 @@ class CGameSystem : public CBaseGameSystem extern CGameSystem g_GameSystem; -// Quick and dirty definition -// MSVC for whatever reason flips overload ordering, and this has three of them -// So this is based on the linux bin which is correct, and MSVC will flip it to match the windows bin, fun -class IEntityResourceManifest -{ -public: - virtual void AddResource(const char*) = 0; - virtual void AddResource(const char*, void*) = 0; - virtual void AddResource(const char*, void*, void*, void*) = 0; - virtual void unk_04() = 0; - virtual void unk_05() = 0; - virtual void unk_06() = 0; - virtual void unk_07() = 0; - virtual void unk_08() = 0; - virtual void unk_09() = 0; - virtual void unk_10() = 0; -}; - abstract_class IGameSystemEventDispatcher{ public : virtual ~IGameSystemEventDispatcher(){} diff --git a/src/idlemanager.cpp b/src/idlemanager.cpp index f1b2c3da..6601003b 100644 --- a/src/idlemanager.cpp +++ b/src/idlemanager.cpp @@ -20,6 +20,7 @@ #include "idlemanager.h" #include "commands.h" #include "cs2fixes.h" +#include "engine2/ivengineserver2.h" #include CIdleSystem* g_pIdleSystem = nullptr; diff --git a/src/idlemanager.h b/src/idlemanager.h index 167f0c29..eff00a1d 100644 --- a/src/idlemanager.h +++ b/src/idlemanager.h @@ -18,7 +18,7 @@ */ #pragma once -#include "convar.h" +#include "tier0/convar.h" extern CConVar g_cvarIdleKickTime; diff --git a/src/leader.cpp b/src/leader.cpp index d0b84b37..d370223a 100644 --- a/src/leader.cpp +++ b/src/leader.cpp @@ -534,7 +534,7 @@ CON_COMMAND_CHAT_LEADER(glow, "[name] [color] - Toggle glow highlight on a playe std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; uint64 iTargetFlags = NO_DEAD; if (!bIsAdmin) @@ -638,7 +638,7 @@ CON_COMMAND_CHAT(vl, " - Vote for a player to become a leader") } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_MULTIPLE | NO_SELF | NO_BOT | NO_IMMUNITY)) return; @@ -689,7 +689,7 @@ CON_COMMAND_CHAT_LEADER(defend, "[name|duration] [duration] - Place a defend mar std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; const char* pszTarget = "@me"; if ((args.ArgC() > 2 || (args.ArgC() == 2 && iDuration == -1)) && (bIsAdmin || g_cvarLeaderCanTargetPlayers.Get())) @@ -720,7 +720,7 @@ CON_COMMAND_CHAT_LEADER(tracer, "[name] [color] - Toggle projectile tracers on a std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; const char* pszTarget = "@me"; if (args.ArgC() >= 2 && (bIsAdmin || g_cvarLeaderCanTargetPlayers.Get())) @@ -776,7 +776,7 @@ CON_COMMAND_CHAT_LEADER(beacon, "[name] [color] - Toggle beacon on a player") std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; uint64 iTargetFlags = NO_DEAD; if (!bIsAdmin) @@ -964,7 +964,7 @@ CON_COMMAND_CHAT_LEADER(leader, "[name] [color] - Force leader status on a playe std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; const char* pszTarget = "@me"; if (args.ArgC() >= 2) @@ -998,7 +998,7 @@ CON_COMMAND_CHAT_FLAGS(removeleader, "[name] - Remove leader status from a playe std::string strCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_MULTIPLE | NO_BOT, nType)) diff --git a/src/map_votes.cpp b/src/map_votes.cpp index 67d990b7..7e4d8696 100644 --- a/src/map_votes.cpp +++ b/src/map_votes.cpp @@ -21,15 +21,15 @@ #include "commands.h" #include "common.h" #include "ctimer.h" +#include "engine2/inetworkgameserver.h" +#include "engine2/ivengineserver2.h" #include "entity/cgamerules.h" #include "eventlistener.h" -#include "iserver.h" #include "mapmigrations.h" #include "playermanager.h" #include "steam/steam_gameserver.h" -#include "strtools.h" -#include "utlstring.h" -#include "utlvector.h" +#include "tier0/tier0_strtools.h" +#include "tier0/utlvector.h" #undef snprintf #include "vendor/nlohmann/json.hpp" #include "votemanager.h" @@ -225,7 +225,7 @@ void CMapVoteSystem::OnLevelInit(const char* pszMapName) m_bIntermissionStarted = false; m_pForcedNextMap = nullptr; - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) ClearPlayerInfo(i); // Delay one tick to override any .cfg's @@ -295,7 +295,7 @@ void CMapVoteSystem::StartVote() } // Reset the player vote counts as the vote just started - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) m_arrPlayerVotes[i] = -1; // Print all available maps out to console @@ -1104,14 +1104,10 @@ bool CMapVoteSystem::IsIntermissionAllowed(bool bCheckOnly) return true; } -CUtlStringList CMapVoteSystem::CreateWorkshopMapGroup() +void CMapVoteSystem::CreateWorkshopMapGroup(CUtlStringList& mapList) { - CUtlStringList mapList; - for (auto pMap : m_vecMapList) mapList.CopyAndAddToTail(pMap->GetDisplayName()); - - return mapList; } bool CMapVoteSystem::WriteMapCooldownsToFile() @@ -1297,7 +1293,7 @@ void CMapVoteSystem::PutMapOnCooldown(const char* pszMapName, float fCooldown) // Add randomness if applicable if (g_cvarVoteMapsCooldown.Get() != 0.0f) { - float flRandomValue = ((float)rand() / RAND_MAX) * g_cvarVoteMapsCooldownRng.Get(); + float flRandomValue = ((float)rand() / (float)RAND_MAX) * g_cvarVoteMapsCooldownRng.Get(); if (rand() % 2) fCooldown += flRandomValue; diff --git a/src/map_votes.h b/src/map_votes.h index e6990288..90db95ad 100644 --- a/src/map_votes.h +++ b/src/map_votes.h @@ -17,11 +17,11 @@ * this program. If not, see . */ -#include "KeyValues.h" #include "common.h" #include "entity/ccsplayercontroller.h" #include "steam/isteamugc.h" #include "steam/steam_api_common.h" +#include "tier0/utlstringlist.h" #undef snprintf #include "vendor/nlohmann/json_fwd.hpp" #include @@ -168,7 +168,7 @@ class CMapVoteSystem CMapVoteSystem() { // Initialize the nomination / vote arrays to -1 - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) { m_arrPlayerNominations[i] = -1; m_arrPlayerVotes[i] = -1; @@ -200,7 +200,7 @@ class CMapVoteSystem bool IsVoteOngoing() { return m_bIsVoteOngoing; } bool IsIntermissionAllowed(bool bCheckOnly = true); bool IsMapListLoaded() { return m_bMapListLoaded; } - CUtlStringList CreateWorkshopMapGroup(); + void CreateWorkshopMapGroup(CUtlStringList& mapList); void QueueMapDownload(PublishedFileId_t iWorkshopId); void StartMapDownload(float flDelay = 0.0f); void PrintDownloadProgress(); @@ -234,10 +234,10 @@ class CMapVoteSystem std::vector> m_vecMapList; std::vector> m_vecGroups; std::vector> m_vecCooldowns; - int m_arrPlayerNominations[MAXPLAYERS]; + int m_arrPlayerNominations[MAX_PLAYERS]; std::shared_ptr m_pForcedNextMap; int m_iRandomWinnerShift = 0; - int m_arrPlayerVotes[MAXPLAYERS]; + int m_arrPlayerVotes[MAX_PLAYERS]; bool m_bIsVoteOngoing = false; bool m_bMapListLoaded = false; bool m_bIntermissionStarted = false; diff --git a/src/mapmigrations.cpp b/src/mapmigrations.cpp index 8e57a8eb..f7f8ec96 100644 --- a/src/mapmigrations.cpp +++ b/src/mapmigrations.cpp @@ -86,10 +86,8 @@ void CMapMigrations::RunMigrations(CUtlVector* pVecEntityKeyV void CMapMigrations::Migrations_Rendermode(CUtlVector* pVecEntityKeyValues) { - FOR_EACH_VEC(*pVecEntityKeyValues, i) + for (auto pKeyValues : *pVecEntityKeyValues) { - auto pKeyValues = (*pVecEntityKeyValues)[i]; - if (!pKeyValues->HasValue("rendermode")) continue; @@ -111,10 +109,8 @@ void CMapMigrations::Migrations_Rendermode(CUtlVector* pVecEn void CMapMigrations::Migrations_20260121(CUtlVector* pVecEntityKeyValues) { - FOR_EACH_VEC(*pVecEntityKeyValues, i) + for (auto pKeyValues : *pVecEntityKeyValues) { - auto pKeyValues = (*pVecEntityKeyValues)[i]; - if (!V_strcasecmp(pKeyValues->GetString("classname"), "func_door_rotating") && pKeyValues->HasValue("spawnflags")) { uint32 spawnFlags = pKeyValues->GetUint("spawnflags"); @@ -170,10 +166,10 @@ void CMapMigrations::Migrations_20260420(CBasePlayerWeapon* pWeapon) bool CMapMigrations::Migrations_20260922(CEntityIdentity* pThis, CUtlSymbolLarge* pInputName, CEntityInstance* pActivator, CEntityInstance* pCaller, variant_t* value) { // Fix stringified Pulse argument packs formatting float decimals breaking logic_case matching post 2026-09-22 CS2 update - if (value->m_type == FIELD_FLOAT32 && !V_strcasecmp(pInputName->String(), "InValue") && !V_strcasecmp(pThis->GetClassname(), "logic_case")) + if (value->GetType() == FIELD_FLOAT32 && !V_strcasecmp(pInputName->String(), "InValue") && !V_strcasecmp(pThis->GetClassname(), "logic_case")) { char szValue[32]; - V_snprintf(szValue, sizeof(szValue), "%g", value->m_float32); + V_snprintf(szValue, sizeof(szValue), "%g", value->Get()); // Back up through CEntityInstance_AcceptInput so we can just worry about variant_t ((CBaseEntity*)pThis->m_pInstance)->AcceptInput(pInputName->String(), szValue, pActivator, pCaller); diff --git a/src/mapmigrations.h b/src/mapmigrations.h index 9c57da3a..ec824c18 100644 --- a/src/mapmigrations.h +++ b/src/mapmigrations.h @@ -19,12 +19,10 @@ #pragma once -#include "KeyValues.h" -#include "convar.h" #include "cs2_sdk/entity/ccsweaponbase.h" #include "ehandle.h" +#include "tier0/convar.h" #include -#undef max extern CConVar g_cvarMapMigrations20260121; diff --git a/src/mempatch.cpp b/src/mempatch.cpp index 2dcd025e..d12008c3 100644 --- a/src/mempatch.cpp +++ b/src/mempatch.cpp @@ -19,9 +19,8 @@ #include "mempatch.h" #include "common.h" -#include "khook.hpp" #include "tier0/dbg.h" -#include "tier1/strtools.h" +#include "tier0/tier0_strtools.h" #include "utils/module.h" #include "tier0/memdbgon.h" diff --git a/src/panoramavote.cpp b/src/panoramavote.cpp index bd7117fd..8f406225 100644 --- a/src/panoramavote.cpp +++ b/src/panoramavote.cpp @@ -23,13 +23,12 @@ #include "common.h" #include "cs2fixes.h" #include "ctimer.h" -#include "engine/igameeventsystem.h" +#include "engine2/igameeventsystem.h" #include "entity/cvotecontroller.h" #include "networksystem/inetworkmessages.h" #include "panoramavote.h" #include "recipientfilters.h" #include "utils/entity.h" -#include "utlstring.h" #include "tier0/memdbgon.h" @@ -97,7 +96,7 @@ bool CPanoramaVoteHandler::IsPlayerInVotePool(int iSlot) if (!m_bIsVoteInProgress) return false; - if (iSlot < 0 || iSlot > MAXPLAYERS) + if (iSlot < 0 || iSlot > MAX_PLAYERS) return false; for (int i = 0; i < m_iVoterCount; i++) @@ -228,7 +227,7 @@ void CPanoramaVoteHandler::InitVoters(CRecipientFilter* pFilter) { // Clear any old info m_iVoterCount = 0; - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) { m_iVoters[i] = -1; hVoteController->m_nVotesCast[i] = VOTE_UNCAST; @@ -240,7 +239,7 @@ void CPanoramaVoteHandler::InitVoters(CRecipientFilter* pFilter) m_iVoterCount = pFilter->GetRecipientCount(); const uint64 x = *reinterpret_cast(&pFilter->GetRecipients()); - for (int i = 0, j = 0; i < MAXPLAYERS; i++) + for (int i = 0, j = 0; i < MAX_PLAYERS; i++) if (x & (static_cast(1u) << i)) m_iVoters[j] = i; } @@ -309,7 +308,7 @@ void CPanoramaVoteHandler::EndVote(YesNoVoteEndReason reason) info.no_votes = hVoteController->m_nVoteOptionCount[VOTE_OPTION2]; info.num_votes = info.yes_votes + info.no_votes; - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) { if (i < m_iVoterCount) { diff --git a/src/panoramavote.h b/src/panoramavote.h index 883414b3..1029b527 100644 --- a/src/panoramavote.h +++ b/src/panoramavote.h @@ -56,12 +56,12 @@ enum YesNoVoteAction #define VOTEINFO_CLIENT_ITEM 1 struct YesNoVoteInfo { - int num_votes; // Number of votes tallied in total - int yes_votes; // Number of votes for yes - int no_votes; // Number of votes for no - int num_clients; // Number of clients who could vote - int clientInfo[MAXPLAYERS][2]; // Client voting info, user VOTEINFO_CLIENT_ defines - // Anything >= [num_clients] is VOTE_NOTINCLUDED, VOTE_UNCAST = client didn't vote + int num_votes; // Number of votes tallied in total + int yes_votes; // Number of votes for yes + int no_votes; // Number of votes for no + int num_clients; // Number of clients who could vote + int clientInfo[MAX_PLAYERS][2]; // Client voting info, user VOTEINFO_CLIENT_ defines + // Anything >= [num_clients] is VOTE_NOTINCLUDED, VOTE_UNCAST = client didn't vote }; // Used to handle events relating to the vote menu @@ -135,7 +135,7 @@ class CPanoramaVoteHandler YesNoVoteHandler m_VoteHandler; YesNoVoteResult m_VoteResult; int m_iVoterCount; - int m_iVoters[MAXPLAYERS]; + int m_iVoters[MAX_PLAYERS]; int m_iCurrentVoteCaller; char m_szCurrentVoteTitle[256]; diff --git a/src/patches.cpp b/src/patches.cpp index 55df3bac..712291e1 100644 --- a/src/patches.cpp +++ b/src/patches.cpp @@ -18,13 +18,7 @@ */ #include "patches.h" -#include "addresses.h" -#include "common.h" -#include "entity/cbasemodelentity.h" -#include "entity/ccsplayercontroller.h" -#include "entity/ccsplayerpawn.h" -#include "icvar.h" -#include "irecipientfilter.h" +#include "tier0/convar.h" #include "tier0/memdbgon.h" diff --git a/src/patches.h b/src/patches.h index 7edf2478..2d454bc9 100644 --- a/src/patches.h +++ b/src/patches.h @@ -1,6 +1,5 @@ #pragma once -#include "gameconfig.h" #include "mempatch.h" extern CMemPatch g_CommonPatches[]; diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 6f932105..4262fd85 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -22,7 +22,9 @@ #include "commands.h" #include "ctime" #include "ctimer.h" -#include "engine/igameeventsystem.h" +#include "engine2/igameeventsystem.h" +#include "engine2/ivengineserver2.h" +#include "engine2/serversideclient.h" #include "entity/ccsplayercontroller.h" #include "entwatch.h" #include "leader.h" @@ -30,11 +32,10 @@ #include "networksystem/inetworkmessages.h" #include "panoramavote.h" #include "recipientfilters.h" -#include "serversideclient.h" +#include "tier0/utlstring.h" #include "tier0/vprof.h" #include "user_preferences.h" #include "utils/entity.h" -#include "utlstring.h" #include "votemanager.h" #include "zombiereborn.h" #include <../cs2fixes.h> @@ -363,7 +364,7 @@ void ZEPlayer::StartBeacon(Color color, ZEPlayerHandle hGiver /* = 0*/) if (pPlayer->m_iTeamNum < CS_TEAM_T || !pPlayer->m_hPlayerPawn->IsAlive() || pPlayer->m_iTeamNum != iTeamNum) { - addresses::UTIL_Remove(pParticle); + pParticle->Remove(); return -1.0f; } @@ -389,7 +390,7 @@ void ZEPlayer::StartBeacon(Color color, ZEPlayerHandle hGiver /* = 0*/) // Remove beacon granted by leader if his leader was stripped if (!pBeaconGiver->IsLeader()) { - addresses::UTIL_Remove(pParticle); + pParticle->Remove(); return -1.0f; } @@ -404,7 +405,7 @@ void ZEPlayer::EndBeacon() CParticleSystem* pParticle = m_hBeaconParticle.Get(); if (pParticle) - addresses::UTIL_Remove(pParticle); + pParticle->Remove(); } // Kills off currently active mark (if exists) and makes a new one. @@ -519,7 +520,7 @@ void ZEPlayer::StartGlow(Color color, int duration) CBaseModelEntity* pModelParent = (CBaseModelEntity*)pParentSceneNode->m_pOwner(); if (pModelParent) - addresses::UTIL_Remove(pModelParent); + pModelParent->Remove(); return -1.0f; } @@ -545,7 +546,7 @@ void ZEPlayer::StartGlow(Color color, int duration) CBaseModelEntity* pModelParent = (CBaseModelEntity*)pParentSceneNode->m_pOwner(); if (pModelParent) - addresses::UTIL_Remove(pModelParent); + pModelParent->Remove(); return -1.0f; }); @@ -568,7 +569,7 @@ void ZEPlayer::EndGlow() CBaseModelEntity* pModelParent = (CBaseModelEntity*)pParentSceneNode->m_pOwner(); if (pModelParent) - addresses::UTIL_Remove(pModelParent); + pModelParent->Remove(); } void ZEPlayer::CycleButtonWatch() @@ -951,8 +952,8 @@ void CPlayerManager::OnClientPutInServer(CPlayerSlot slot) CServerSideClient* pClient = GetClientBySlot(slot); - if (pClient && pClient->m_vecLoadedSpawnGroups.Count() != vecActualSpawnGroups.Count()) - pClient->m_vecLoadedSpawnGroups = vecActualSpawnGroups; + if (pClient && pClient->m_LoadedSpawnGroups.Count() != vecActualSpawnGroups.Count()) + pClient->m_LoadedSpawnGroups = vecActualSpawnGroups; } void CPlayerManager::OnLateLoad() @@ -1226,9 +1227,9 @@ void CPlayerManager::SetupInfiniteAmmo() CUtlVector>* weapons = pWeaponServices->m_hMyWeapons(); - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* weapon = (*weapons)[i].Get(); + CBasePlayerWeapon* weapon = hWeapon.Get(); if (!weapon) continue; @@ -1821,7 +1822,7 @@ bool CPlayerManager::CanTargetPlayers(CCSPlayerController* pPlayer, const char* ZEPlayer* CPlayerManager::GetPlayer(CPlayerSlot slot) { - if (slot.Get() < 0 || slot.Get() >= MAXPLAYERS) + if (slot.Get() < 0 || slot.Get() >= MAX_PLAYERS) return nullptr; return m_vecPlayers[slot.Get()]; @@ -1837,7 +1838,7 @@ ZEPlayer* CPlayerManager::GetPlayerFromUserId(uint16 userid) { uint8 index = userid & 0xFF; - if (index >= MAXPLAYERS) + if (index >= MAX_PLAYERS) return nullptr; return m_vecPlayers[index]; @@ -1980,10 +1981,8 @@ int CPlayerManager::GetOnlinePlayerCount(bool bCountBots) if (GetGlobals()) flLastUpdateTime = GetGlobals()->curtime; - for (int i = 0; i < GetClientList()->Count(); i++) + for (CServerSideClient* pClient : *GetClientList()) { - CServerSideClient* pClient = (*GetClientList())[i]; - if (pClient && pClient->GetSignonState() >= SIGNONSTATE_CONNECTED && (bCountBots || !pClient->IsFakeClient())) iOnlinePlayers++; } @@ -1998,6 +1997,6 @@ void CPlayerManager::FullUpdateAllClients() if (!pClients) return; - FOR_EACH_VEC(*pClients, i) - (*pClients)[i]->ForceFullUpdate(); + for (auto pClient : *pClients) + pClient->m_nDeltaTick = -1; } \ No newline at end of file diff --git a/src/playermanager.h b/src/playermanager.h index ee7eac18..9753fec7 100644 --- a/src/playermanager.h +++ b/src/playermanager.h @@ -18,7 +18,6 @@ */ #pragma once -#include "bitvec.h" #include "common.h" #include "entity/cparticlesystem.h" #include "entity/cpointorient.h" @@ -30,7 +29,8 @@ #include "steam/isteamuser.h" #include "steam/steam_api_common.h" #include "steam/steamclientpublic.h" -#include "utlvector.h" +#include "tier0/bitvec.h" +#include "tier0/utlvector.h" #include extern CConVar g_cvarFlashLightTransmitOthers; @@ -369,7 +369,7 @@ class ZEPlayer uint64 m_iAdminFlags; int m_iAdminImmunity; int m_iHideDistance; - CBitVec m_shouldTransmit; + CBitVec m_shouldTransmit; int m_iTotalDamage; int m_iTotalHits; int m_iTotalHeadshots; @@ -484,7 +484,7 @@ class CPlayerManager STEAM_GAMESERVER_CALLBACK_MANUAL(CPlayerManager, OnValidateAuthTicket, ValidateAuthTicketResponse_t, m_CallbackValidateAuthTicketResponse); private: - ZEPlayer* m_vecPlayers[MAXPLAYERS]; + ZEPlayer* m_vecPlayers[MAX_PLAYERS]; uint64 m_nUsingStopSound; uint64 m_nUsingSilenceSound; diff --git a/src/recipientfilters.h b/src/recipientfilters.h index 15500e67..06a3dd4e 100644 --- a/src/recipientfilters.h +++ b/src/recipientfilters.h @@ -49,7 +49,7 @@ class CRecipientFilter : public IRecipientFilter { m_Recipients.ClearAll(); - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) { if (!g_playerManager->GetPlayer(i)) continue; diff --git a/src/topdefender.cpp b/src/topdefender.cpp index 92fc5000..c08ad3af 100644 --- a/src/topdefender.cpp +++ b/src/topdefender.cpp @@ -21,7 +21,6 @@ #include "commands.h" #include "common.h" #include "ctimer.h" -#include "detours.h" #include "entity/ccsplayercontroller.h" #include "idlemanager.h" #include "playermanager.h" @@ -323,7 +322,7 @@ void TopDefenderSearch(CCSPlayerController* player, const CCommand& args) if (iRank <= 0 || iRank > sortedPlayers.size()) { int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_MULTIPLE)) return; diff --git a/src/user_preferences.cpp b/src/user_preferences.cpp index 27f41e47..bb694e16 100644 --- a/src/user_preferences.cpp +++ b/src/user_preferences.cpp @@ -23,7 +23,7 @@ #include "entwatch.h" #include "httpmanager.h" #include "playermanager.h" -#include "strtools.h" +#include "tier0/tier0_strtools.h" #include "zombiereborn.h" #include #undef snprintf diff --git a/src/user_preferences.h b/src/user_preferences.h index 5064c129..eff18b21 100644 --- a/src/user_preferences.h +++ b/src/user_preferences.h @@ -19,7 +19,6 @@ #pragma once #include "common.h" -#include "utlstring.h" #include #undef snprintf #include "vendor/nlohmann/json_fwd.hpp" @@ -56,6 +55,7 @@ class CPreferenceValue class CUserPreferencesStorage { public: + virtual ~CUserPreferencesStorage() = default; virtual void LoadPreferences(uint64 iSteamId, StorageCallback_t cb) = 0; virtual void StorePreferences(uint64 iSteamId, UserPrefsMap_t& preferences, StorageCallback_t cb) = 0; }; @@ -75,7 +75,7 @@ class CUserPreferencesSystem public: CUserPreferencesSystem() { - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) { m_mUserSteamIds[i] = 0; m_mPreferencesLoaded[i] = false; @@ -96,9 +96,9 @@ class CUserPreferencesSystem void PushPreferences(int iSlot); private: - UserPrefsMap_t m_mPreferencesMaps[MAXPLAYERS]; - uint64 m_mUserSteamIds[MAXPLAYERS]; - bool m_mPreferencesLoaded[MAXPLAYERS]; + UserPrefsMap_t m_mPreferencesMaps[MAX_PLAYERS]; + uint64 m_mUserSteamIds[MAX_PLAYERS]; + bool m_mPreferencesLoaded[MAX_PLAYERS]; }; extern CUserPreferencesSystem* g_pUserPreferencesSystem; \ No newline at end of file diff --git a/src/utils/entity.h b/src/utils/entity.h index 06ffbaa0..fad7d4fa 100644 --- a/src/utils/entity.h +++ b/src/utils/entity.h @@ -20,10 +20,8 @@ #pragma once #include "../addresses.h" -#include "datamap.h" +#include "entity2/variant.h" #include "platform.h" -#include "string_t.h" -#include "variant.h" class CEntityInstance; class CBaseEntity; diff --git a/src/utils/hud_manager.cpp b/src/utils/hud_manager.cpp index 58dde4ce..24e0f87c 100644 --- a/src/utils/hud_manager.cpp +++ b/src/utils/hud_manager.cpp @@ -21,7 +21,7 @@ #include "../cs2fixes.h" #include "../ctimer.h" #include "../recipientfilters.h" -#include "engine/igameeventsystem.h" +#include "engine2/igameeventsystem.h" #include "entity/cgamerules.h" #include "gameevents.pb.h" #include "networksystem/inetworkmessages.h" diff --git a/src/utils/khook_helpers.h b/src/utils/khook_helpers.h index fd004856..3725dde0 100644 --- a/src/utils/khook_helpers.h +++ b/src/utils/khook_helpers.h @@ -23,6 +23,7 @@ class CKHookBase { public: + virtual ~CKHookBase() = default; virtual void Configure() = 0; }; diff --git a/src/utils/module.h b/src/utils/module.h index 543af18d..4db6bd95 100644 --- a/src/utils/module.h +++ b/src/utils/module.h @@ -22,7 +22,7 @@ #include "dbg.h" #include "interface.h" #include "plat.h" -#include "strtools.h" +#include "tier0/tier0_strtools.h" #include #include diff --git a/src/utils/plat_unix.cpp b/src/utils/plat_unix.cpp index 7bcab072..56e798da 100644 --- a/src/utils/plat_unix.cpp +++ b/src/utils/plat_unix.cpp @@ -25,16 +25,17 @@ #include "module.h" #include "plat.h" #include "sys/mman.h" + #include #include #include #include - #include #include - #include #include + #include #include #include #include + #include #include "tier0/memdbgon.h" diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index b2114219..c6e640b3 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -20,6 +20,7 @@ #include "utils.h" #include "../cs2fixes.h" #include "../gameconfig.h" +#include "engine2/ivengineserver2.h" void Message(const char* msg, ...) { diff --git a/src/utils/utils.h b/src/utils/utils.h index 24d16c66..04ad3fa7 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -21,7 +21,7 @@ #include "playerslot.h" #include "steam/isteamugc.h" -#include "utlvector.h" +#include "tier0/utlvector.h" #include class CServerSideClient; diff --git a/src/utils/vscript_function.cpp b/src/utils/vscript_function.cpp index 5519b81a..32b97b0d 100644 --- a/src/utils/vscript_function.cpp +++ b/src/utils/vscript_function.cpp @@ -34,9 +34,8 @@ void* GetVScriptFunction(ScriptClassDesc_t* pScriptDesc, const char* pszFuncName }; const auto& functionBindings = *reinterpret_cast*>(&pScriptDesc->m_FunctionBindings); - FOR_EACH_VEC(functionBindings, i) + for (auto& functionBinding : functionBindings) { - auto& functionBinding = functionBindings.Element(i); if (V_strcmp(functionBinding.m_desc.m_pszScriptName, pszFuncName) != 0) continue; diff --git a/src/virtual_hooks.cpp b/src/virtual_hooks.cpp index 617744b4..7f8076eb 100644 --- a/src/virtual_hooks.cpp +++ b/src/virtual_hooks.cpp @@ -19,7 +19,6 @@ #include "virtual_hooks.h" #include "adminsystem.h" -#include "cchecktransmitinfo.h" #include "cfgparser.h" #include "commands.h" #include "common.h" @@ -27,7 +26,10 @@ #include "cs_gameevents.pb.h" #include "cstrike15_usermessages.pb.h" #include "ctimer.h" -#include "engine/IEngineService.h" +#include "engine2/iengineservicemgr.h" +#include "engine2/inetworkgameserver.h" +#include "engine2/ivengineserver2.h" +#include "engine2/serversideclient.h" #include "entities.h" #include "entity/ccsplayercontroller.h" #include "entity/customhudlayout.h" @@ -38,9 +40,7 @@ #include "eventlistener.h" #include "gameconfig.h" #include "gameevents.pb.h" -#include "icvar.h" #include "idlemanager.h" -#include "iserver.h" #include "khook_helpers.h" #include "leader.h" #include "map_votes.h" @@ -49,7 +49,7 @@ #include "networkstringtabledefs.h" #include "panoramavote.h" #include "playermanager.h" -#include "serversideclient.h" +#include "tier0/icvar.h" #include "tier0/vprof.h" #include "usermessages.pb.h" #include "votemanager.h" @@ -79,7 +79,7 @@ KHOOK_VIRTUAL(SwitchToLoop, &IEngineServiceMgr::SwitchToLoop, g_pEngineServiceMg KHook::Virtual createWorkshopMapGroupHook(0U, Hook_CreateWorkshopMapGroup, nullptr); KHook::Virtual loadEventsFromFileHook(&IGameEventManager2::LoadEventsFromFile, Hook_LoadEventsFromFile, nullptr); -KHook::Virtual processVoiceDataHook(&CServerSideClient::ProcessVoiceData, Hook_ProcessVoiceData, nullptr); +KHook::Virtual&> processVoiceDataHook(&CServerSideClient::ProcessVoiceData, Hook_ProcessVoiceData, nullptr); KHook::Virtual setGameSpawnGroupMgrHook(&INetworkGameServer::SetGameSpawnGroupMgr, Hook_SetGameSpawnGroupMgr, nullptr); KHook::Virtual*, bool> getTouchingListHook(0U, nullptr, Hook_GetTouchingList_Post); KHook::Virtual checkMovingGroundHook(0U, Hook_CheckMovingGround, nullptr); @@ -556,7 +556,7 @@ KHook::Return Hook_CheckTransmit_Post(ISource2GameEntities* pThis, CCheckT for (int i = 0; i < infoCount; i++) { - auto& pInfo = (CCheckTransmitInfoExtended*&)(ppInfoList[i]); + CCheckTransmitInfo* pInfo = ppInfoList[i]; CCSPlayerController* pSelfController = CCSPlayerController::FromSlot(pInfo->m_nPlayerSlot); if (!pSelfController || !pSelfController->IsConnected()) @@ -603,7 +603,7 @@ KHook::Return Hook_CheckTransmit_Post(ISource2GameEntities* pThis, CCheckT if (pSelfZEPlayer->ShouldBlockTransmit(j) && pOtherZEPlayer && !pOtherZEPlayer->IsLeader() && g_pEWHandler->FindItemInstanceByOwner(j, false, 0) == -1) { pInfo->m_pTransmitEntity->Clear(pPawn->entindex()); - pInfo->m_pTransmitNonPlayers->Set(pPawn->entindex()); + pInfo->m_pNonTransmitEntity->Set(pPawn->entindex()); } } @@ -733,7 +733,11 @@ KHook::Return Hook_SwitchToLoop(IEngineServiceMgr* pThis, const char* pszL KHook::Return Hook_CreateWorkshopMapGroup(IGameTypes* pThis, const char* name, const CUtlStringList& mapList) { if (g_cvarVoteManagerEnable.Get() && g_pMapVoteSystem->IsMapListLoaded()) - return KHook::Recall(nullptr, {KHook::Action::Ignore}, pThis, name, g_pMapVoteSystem->CreateWorkshopMapGroup()); + { + CUtlStringList workshopMapList; + g_pMapVoteSystem->CreateWorkshopMapGroup(workshopMapList); + return KHook::Recall(nullptr, {KHook::Action::Ignore}, pThis, name, workshopMapList); + } return {KHook::Action::Ignore}; } @@ -745,7 +749,7 @@ KHook::Return Hook_LoadEventsFromFile(IGameEventManager2* pThis, const char return {KHook::Action::Ignore}; } -KHook::Return Hook_ProcessVoiceData(CServerSideClient* pClient, const CCLCMsg_VoiceData_t& msg) +KHook::Return Hook_ProcessVoiceData(CServerSideClient* pClient, const CNetMessagePB& msg) { ZEPlayer* pPlayer = g_playerManager->GetPlayer(pClient->GetPlayerSlot()); @@ -813,9 +817,8 @@ KHook::Return Hook_GetTouchingList_Post(CVPhys2World* pThis, CUtlVector touchingLinks; std::vector unTouchLinks; - FOR_EACH_VEC(*pList, i) + for (const auto& link : *pList) { - const auto& link = pList->Element(i); if (link.IsUnTouching()) unTouchLinks.push_back(link); else @@ -855,7 +858,7 @@ KHook::Return Hook_CheckMovingGround(CCSPlayer_MovementServices* pThis, do int iSlot = pController->GetPlayerSlot(); - static int aPlayerTicks[MAXPLAYERS] = {0}; + static int aPlayerTicks[MAX_PLAYERS] = {0}; // The point of doing this is to avoid running the function (and applying/resetting basevelocity) multiple times per tick // This can happen when the client or server lags diff --git a/src/virtual_hooks.h b/src/virtual_hooks.h index 46b12042..f1ba5e90 100644 --- a/src/virtual_hooks.h +++ b/src/virtual_hooks.h @@ -19,12 +19,16 @@ #pragma once -#include "cs2_sdk/netmessages.h" -#include "engine/igameeventsystem.h" +#include "engine2/igameeventsystem.h" +#include "engine2/inetworkgameserver.h" +#include "engine2/inetworkserverservice.h" +#include "engine2/isource2server.h" #include "entity/cgamerules.h" #include "igameevents.h" -#include "iserver.h" #include "khook.hpp" +#include "netmessages.pb.h" +#include "networksystem/inetworkmessages.h" +#include "tier0/utlstringlist.h" class CCSPlayer_MovementServices; class CServerSideClient; @@ -61,7 +65,7 @@ KHook::Return Hook_DispatchConCommand(ICvar* pThis, ConCommandRef cmd, con KHook::Return Hook_SwitchToLoop(IEngineServiceMgr* pThis, const char* pszLoopModeName, KeyValues* pKV, uint32 nId, const char* pszAddonName, bool bUnk); KHook::Return Hook_CreateWorkshopMapGroup(IGameTypes* pThis, const char* name, const CUtlStringList& mapList); KHook::Return Hook_LoadEventsFromFile(IGameEventManager2* pThis, const char* filename, bool bSearchAll); -KHook::Return Hook_ProcessVoiceData(CServerSideClient* pClient, const CCLCMsg_VoiceData_t& msg); +KHook::Return Hook_ProcessVoiceData(CServerSideClient* pClient, const CNetMessagePB& msg); KHook::Return Hook_SetGameSpawnGroupMgr(INetworkGameServer* pThis, IGameSpawnGroupMgr* pSpawnGroupMgr); KHook::Return Hook_GetTouchingList_Post(CVPhys2World* pThis, CUtlVector* pList, bool unknown); KHook::Return Hook_CheckMovingGround(CCSPlayer_MovementServices* pThis, double frametime); diff --git a/src/votemanager.cpp b/src/votemanager.cpp index 786d699d..e9c681e3 100644 --- a/src/votemanager.cpp +++ b/src/votemanager.cpp @@ -21,8 +21,8 @@ #include "commands.h" #include "ctimer.h" #include "entity/cgamerules.h" -#include "icvar.h" #include "playermanager.h" +#include "tier0/convar.h" #include "tier0/memdbgon.h" @@ -563,7 +563,7 @@ void CVoteManager::ExtendMap(int iMinutes, bool bIncrementiExtends, bool bAllowE { m_iExtends++; - for (int i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAX_PLAYERS; i++) { ZEPlayer* pPlayer = g_playerManager->GetPlayer(i); if (pPlayer) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index f7e5e5d3..a180a260 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -22,9 +22,10 @@ #include "commands.h" #include "ctimer.h" #include "customio.h" -#include "engine/igameeventsystem.h" +#include "engine2/igameeventsystem.h" +#include "engine2/ivengineserver2.h" +#include "engine2/serversideclient.h" #include "entity/cgamerules.h" -#include "entity/cparticlesystem.h" #include "entity/cteam.h" #include "entity/services.h" #include "eventlistener.h" @@ -33,8 +34,6 @@ #include "networksystem/inetworkmessages.h" #include "playermanager.h" #include "recipientfilters.h" -#include "serversideclient.h" -#include "tier0/vprof.h" #include "user_preferences.h" #include "utils/entity.h" #include "vendor/nlohmann/json.hpp" @@ -1082,9 +1081,9 @@ void ZR_StripAndGiveKnife(CCSPlayerPawn* pPawn) CUtlVector>* weapons = pWeaponServices->m_hMyWeapons(); - FOR_EACH_VEC(*weapons, i) + for (const auto& hWeapon : *weapons) { - CBasePlayerWeapon* pWeapon = (*weapons)[i].Get(); + CBasePlayerWeapon* pWeapon = hWeapon.Get(); if (pWeapon && pWeapon->GetWeaponVData()->m_GearSlot() == GEAR_SLOT_KNIFE) { @@ -1164,17 +1163,17 @@ std::vector ZR_GetSpawns() auto ctSpawns = g_pGameRules->m_CTSpawnPoints(); auto tSpawns = g_pGameRules->m_TerroristSpawnPoints(); - FOR_EACH_VEC(*ctSpawns, i) + for (const auto& hSpawn : *ctSpawns) { - SpawnPoint* pSpawn = (*ctSpawns)[i].Get(); + SpawnPoint* pSpawn = hSpawn.Get(); if (pSpawn) spawns.push_back(pSpawn); } - FOR_EACH_VEC(*tSpawns, i) + for (const auto& hSpawn : *tSpawns) { - SpawnPoint* pSpawn = (*tSpawns)[i].Get(); + SpawnPoint* pSpawn = hSpawn.Get(); if (pSpawn) spawns.push_back(pSpawn); @@ -1295,7 +1294,7 @@ void ZR_InitialInfection() // the num of mz to infect int iMZToInfect = vecCandidateControllers.size() / g_cvarInfectSpawnMZRatio.Get(); iMZToInfect = g_cvarInfectSpawnMinCount.Get() > iMZToInfect ? g_cvarInfectSpawnMinCount.Get() : iMZToInfect; - bool vecIsMZ[MAXPLAYERS] = {false}; + bool vecIsMZ[MAX_PLAYERS] = {false}; if (vecCandidateControllers.size() < g_cvarInfectSpawnMinCountReq.Get()) iMZToInfect = 0; @@ -2013,7 +2012,7 @@ CON_COMMAND_CHAT_FLAGS(infect, "- Infect a player", ADMFLAG_GENERIC) } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_TERRORIST | NO_DEAD, nType)) @@ -2073,7 +2072,7 @@ CON_COMMAND_CHAT_FLAGS(revive, "- Revive a player", ADMFLAG_GENERIC) } int iNumClients = 0; - int pSlots[MAXPLAYERS]; + int pSlots[MAX_PLAYERS]; ETargetType nType; if (!g_playerManager->CanTargetPlayers(player, args[1], iNumClients, pSlots, NO_DEAD | NO_COUNTER_TERRORIST, nType)) diff --git a/src/zombiereborn.h b/src/zombiereborn.h index 84b6005f..12825f70 100644 --- a/src/zombiereborn.h +++ b/src/zombiereborn.h @@ -231,7 +231,7 @@ class CZRPlayerClassManager // These exist so we can iterate the class maps in insertion order std::vector m_ZombieClassKeys; std::vector m_HumanClassKeys; - std::weak_ptr m_vecRegenTimers[MAXPLAYERS]; + std::weak_ptr m_vecRegenTimers[MAX_PLAYERS]; }; extern CZRPlayerClassManager* g_pZRPlayerClassManager; From e92a2f54fa9dad405d6632a81c55770eeab1956d Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 15 Oct 2026 03:06:57 -0400 Subject: [PATCH 5/9] Fix score changes not being networked --- src/cs2_sdk/entity/ccsplayercontroller.h | 2 +- src/leader.cpp | 4 ++-- src/topdefender.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cs2_sdk/entity/ccsplayercontroller.h b/src/cs2_sdk/entity/ccsplayercontroller.h index 9464c0e8..fae1ace1 100644 --- a/src/cs2_sdk/entity/ccsplayercontroller.h +++ b/src/cs2_sdk/entity/ccsplayercontroller.h @@ -144,7 +144,7 @@ class CCSPlayerController : public CBasePlayerController void AddScore(int iScore) { - m_iScore() = m_iScore() + iScore; + m_iScore = m_iScore() + iScore; } void SetClanTag(const char* pszClanTag) diff --git a/src/leader.cpp b/src/leader.cpp index d370223a..251e87b3 100644 --- a/src/leader.cpp +++ b/src/leader.cpp @@ -195,7 +195,7 @@ static bool Leader_SetNewLeader(ZEPlayer* zpLeader, std::string strColor = "") if (zpLeader->IsLeader()) return false; - pLeader->m_iScore() = pLeader->m_iScore() + g_cvarLeaderExtraScore.Get(); + pLeader->m_iScore = pLeader->m_iScore() + g_cvarLeaderExtraScore.Get(); zpLeader->SetLeader(true); Color color = Color(0, 0, 0, 0); @@ -295,7 +295,7 @@ static void RemoveLeader(CCSPlayerController* ccsLeader) if (!zpLeader || !zpLeader->IsLeader()) return; - ccsLeader->m_iScore() = ccsLeader->m_iScore() - g_cvarLeaderExtraScore.Get(); + ccsLeader->m_iScore = ccsLeader->m_iScore() - g_cvarLeaderExtraScore.Get(); zpLeader->SetLeader(false); zpLeader->SetLeaderColor(Color(0, 0, 0, 0)); zpLeader->SetTracerColor(Color(0, 0, 0, 0)); diff --git a/src/topdefender.cpp b/src/topdefender.cpp index c08ad3af..262d9c4c 100644 --- a/src/topdefender.cpp +++ b/src/topdefender.cpp @@ -135,7 +135,7 @@ void TD_OnRoundStart(IGameEvent* pEvent) // If player is top defender, we set their score and clan tag if (g_cvarTopDefenderScore.Get() > 0 && pPlayer->GetTopDefenderStatus()) { - pController->m_iScore() = pController->m_iScore() + g_cvarTopDefenderScore.Get(); + pController->m_iScore = pController->m_iScore() + g_cvarTopDefenderScore.Get(); pController->SetClanTag(g_cvarTopDefenderClanTag.Get().String()); } } @@ -210,7 +210,7 @@ void TD_OnRoundEnd(IGameEvent* pEvent) if (pController) { pPlayer->SetTopDefenderStatus(false); - pController->m_iScore() = pController->m_iScore() - g_cvarTopDefenderScore.Get(); + pController->m_iScore = pController->m_iScore() - g_cvarTopDefenderScore.Get(); pController->ResetClanTag(); } } From c355d83829e24e2569b3ecf5c6570de078462ef1 Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 15 Oct 2026 03:15:46 -0400 Subject: [PATCH 6/9] Fix some loop errors in panorama votes --- src/panoramavote.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panoramavote.cpp b/src/panoramavote.cpp index 8f406225..4fe5faf3 100644 --- a/src/panoramavote.cpp +++ b/src/panoramavote.cpp @@ -96,7 +96,7 @@ bool CPanoramaVoteHandler::IsPlayerInVotePool(int iSlot) if (!m_bIsVoteInProgress) return false; - if (iSlot < 0 || iSlot > MAX_PLAYERS) + if (iSlot < 0 || iSlot >= MAX_PLAYERS) return false; for (int i = 0; i < m_iVoterCount; i++) @@ -241,7 +241,7 @@ void CPanoramaVoteHandler::InitVoters(CRecipientFilter* pFilter) const uint64 x = *reinterpret_cast(&pFilter->GetRecipients()); for (int i = 0, j = 0; i < MAX_PLAYERS; i++) if (x & (static_cast(1u) << i)) - m_iVoters[j] = i; + m_iVoters[j++] = i; } void CPanoramaVoteHandler::CheckForEarlyVoteClose() From 68504a135fae431060992f32c58249b8b1840ce5 Mon Sep 17 00:00:00 2001 From: Vauff Date: Thu, 15 Oct 2026 21:04:25 -0400 Subject: [PATCH 7/9] Rework cvar whitelist for 2026-10-14 CS2 update compatibility --- configs/cvar_whitelist.jsonc.example | 47 ++++++++++++++++++++++---- gamedata/cs2fixes.jsonc | 8 ++--- src/addresses.cpp | 47 ++++++++++++++++---------- src/addresses.h | 5 ++- src/cs2fixes.cpp | 1 + src/cvarwhitelist.cpp | 49 +++++++++++++++++++--------- src/cvarwhitelist.h | 10 +++++- src/detours.cpp | 12 ------- src/detours.h | 1 - src/gamesystem.cpp | 47 ++++---------------------- src/playermanager.cpp | 2 -- src/virtual_hooks.cpp | 2 -- 12 files changed, 127 insertions(+), 104 deletions(-) diff --git a/configs/cvar_whitelist.jsonc.example b/configs/cvar_whitelist.jsonc.example index e2efb939..7d9c477b 100644 --- a/configs/cvar_whitelist.jsonc.example +++ b/configs/cvar_whitelist.jsonc.example @@ -106,18 +106,22 @@ "cl_crosshair_sniper_show_normal_inaccuracy": true, "cl_crosshair_sniper_width": true, "cl_crosshair_t": true, - "cl_crosshairalpha": true, - "cl_crosshaircolor": true, "cl_crosshaircolor_b": true, "cl_crosshaircolor_g": true, "cl_crosshaircolor_r": true, + "cl_crosshaircolor_a": true, + "cl_crosshairoutline_b": true, + "cl_crosshairoutline_g": true, + "cl_crosshairoutline_r": true, + "cl_crosshairoutline_a": true, "cl_crosshairdot": true, - "cl_crosshairgap": true, - "cl_crosshairgap_useweaponvalue": true, - "cl_crosshairsize": true, + "cl_crosshair_gap": true, + "cl_crosshair_length": true, + "cl_crosshair_thickness": true, + "cl_crosshair_dynamic_spread_limit": true, "cl_crosshairstyle": true, - "cl_crosshairthickness": true, - "cl_crosshairusealpha": true, + "cl_ironsight_usecrosshaircolor": true, + "cl_ironsight_dot_scale": true, "cl_draw_only_deathnotices": true, "cl_drawhud": true, "cl_drawhud_force_deathnotices": true, @@ -528,6 +532,35 @@ "radio1": true, "radio2": true, "radio3": true, + "coverme": true, + "takepoint": true, + "holdpos": true, + "regroup": true, + "followme": true, + "takingfire": true, + "go": true, + "fallback": true, + "sticktog": true, + "cheer": true, + "thanks": true, + "compliment": true, + "getinpos": true, + "stormfront": true, + "report": true, + "roger": true, + "enemyspot": true, + "needbackup": true, + "sectorclear": true, + "inposition": true, + "reportingin": true, + "getout": true, + "negative": true, + "enemydown": true, + "throwsmokes": true, + "throwgrenades": true, + "throwfire": true, + "go_to_bombsite_a": true, + "go_to_bombsite_b": true, "player_ping": true, "mp_teamlogo_1": true, "mp_teamlogo_2": true, diff --git a/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index 8e6877ce..d3e74c63 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -347,12 +347,12 @@ "windows": "48 8B C4 48 89 58 ? 57 48 81 EC ? ? ? ? 0F 29 70 ? 48 8B FA 0F 29 78 ? 48 8B D9", "linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 F4 53 48 89 FB 48 81 EC ? ? ? ? 66 0F 1F 44 00" }, - // Only called in an if statement by function with "DISALLOWED WORKSHOP CONVAR: %s" string - "IsCommandWhitelisted": + // CUtlSymbolTable filled from "whitelist_cvars", passed to CUtlSymbolTable::Find in function with "DISALLOWED WORKSHOP CONVAR: %s" string + "CCSAddonManager__CommandWhitelist": { "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" + "windows": "48 8D 0D ? ? ? ? FF 15 ? ? ? ? B9 ? ? ? ? 66 39 08 0F 85", + "linux": "48 8D 35 ? ? ? ? 48 89 DF E8 ? ? ? ? 66 83 BD" }, // "CWorldRendererMgr::CreateWorld_Internal( %s ): Blocking load because marked for deletion during load" "CWorldRendererMgr_CreateWorld_Internal": diff --git a/src/addresses.cpp b/src/addresses.cpp index e49c4fcd..6b5b785c 100644 --- a/src/addresses.cpp +++ b/src/addresses.cpp @@ -82,33 +82,21 @@ bool addresses::Initialize() RESOLVE_SIG("CBasePlayerPawn_SnapViewAngles", addresses::CBasePlayerPawn_SnapViewAngles); RESOLVE_SIG("CBaseEntity_TakeDamageOld", addresses::CBaseEntity_TakeDamageOld); - return InitializeBanMap(); + return InitializeRipRelativeAddresses(); } -bool addresses::InitializeBanMap() +bool addresses::InitializeRipRelativeAddresses() { - // This signature directly points to the instruction referencing sm_mapGcBanInformation - uintptr_t pAddr = (uintptr_t)g_GameConfig->ResolveSignature("CCSGameRules__sm_mapGcBanInformation"); + addresses::sm_mapGcBanInformation = (decltype(addresses::sm_mapGcBanInformation))ResolveRipRelative("CCSGameRules__sm_mapGcBanInformation"); - if (!pAddr) + if (!addresses::sm_mapGcBanInformation) return false; - // the opcode is 3 bytes so we skip those - pAddr += 3; - - // Grab the offset as 4 bytes - uint32 offset = *(uint32*)pAddr; - - // Go to the next instruction, which is what the relative address is based off - pAddr += 4; - - // Get the real address - addresses::sm_mapGcBanInformation = (decltype(addresses::sm_mapGcBanInformation))(pAddr + offset); + addresses::CCSAddonManager_CommandWhitelist = (CUtlSymbolTable*)ResolveRipRelative("CCSAddonManager__CommandWhitelist"); - if (!addresses::sm_mapGcBanInformation) + if (!addresses::CCSAddonManager_CommandWhitelist) return false; - Message("Found %s at 0x%p\n", "CCSGameRules__sm_mapGcBanInformation", addresses::sm_mapGcBanInformation); return true; } @@ -133,3 +121,26 @@ bool addresses::InitializeVScriptFunctions() return true; } + +void* addresses::ResolveRipRelative(const char* pszName, int nOpcodeSize) +{ + uintptr_t pAddr = (uintptr_t)g_GameConfig->ResolveSignature(pszName); + + if (!pAddr) + return nullptr; + + // Skip the opcode, usually 3 bytes for 64-bit operands + pAddr += nOpcodeSize; + + // Grab the offset as 4 bytes + int32 offset = *(int32*)pAddr; + + // Go to the next instruction, which is what the relative address is based off + pAddr += 4; + + // Get the real address + void* pResult = (void*)(pAddr + offset); + + Message("Found %s at 0x%p\n", pszName, pResult); + return pResult; +} diff --git a/src/addresses.h b/src/addresses.h index 6bbce1e1..0ce51873 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -58,6 +58,7 @@ class CGameRules; class CEntityKeyValues; class IRecipientFilter; class CTakeDamageInfo; +class CUtlSymbolTable; class CCSPlayer_WeaponServices; class CBasePlayerWeapon; class CSpawnGroupMgrGameSystem; @@ -79,10 +80,12 @@ struct CGcBanInformation_t namespace addresses { bool Initialize(); - bool InitializeBanMap(); + bool InitializeRipRelativeAddresses(); bool InitializeVScriptFunctions(); + void* ResolveRipRelative(const char* pszName, int nOpcodeSize = 3); inline CUtlOrderedMap* sm_mapGcBanInformation; + inline CUtlSymbolTable* CCSAddonManager_CommandWhitelist; inline void(FASTCALL* SetGroundEntity)(CBaseEntity* ent, CBaseEntity* ground, CBaseEntity* unk3); inline void(FASTCALL* CCSPlayerController_SwitchTeam)(CCSPlayerController* pController, uint32 team); diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 31f14648..ae84d71d 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -368,6 +368,7 @@ void CS2Fixes::OnLevelInit(char const* pMapName, g_playerManager->SetupInfiniteAmmo(); g_pMapVoteSystem->OnLevelInit(pMapName); + g_pConvarWhitelist->ApplyToGameTable(pMapName); if (g_cvarEnableZR.Get()) ZR_OnLevelInit(); diff --git a/src/cvarwhitelist.cpp b/src/cvarwhitelist.cpp index 3fe5a958..ee64d0a8 100644 --- a/src/cvarwhitelist.cpp +++ b/src/cvarwhitelist.cpp @@ -18,11 +18,13 @@ */ #include "cvarwhitelist.h" +#include "addresses.h" #include "commands.h" #include "utils.h" #undef snprintf #include "vendor/nlohmann/json.hpp" #include +#include CConVarWhitelist* g_pConvarWhitelist = nullptr; @@ -33,10 +35,15 @@ CON_COMMAND_CHAT_FLAGS(cvarwhitelist_reload, "- Reload the ConVar whitelist conf if (!g_cvarConVarWhitelistEnable.Get()) return; - if (g_pConvarWhitelist->LoadConfig()) + if (g_pConvarWhitelist->LoadConfig() && GetGlobals()) + { + g_pConvarWhitelist->ApplyToGameTable(GetGlobals()->mapname.ToCStr()); ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "ConVar whitelist config reloaded!"); + } else + { ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Failed to reload ConVar whitelist config!"); + } } bool CConVarWhitelist::LoadConfig() @@ -98,25 +105,35 @@ bool CConVarWhitelist::LoadConfig() return true; } -bool CConVarWhitelist::IsWhitelisted(std::string strName) +void CConVarWhitelist::ApplyToGameTable(const char* pszMapName) { - auto globalIt = std::find_if(m_vecGlobalWhitelist.begin(), m_vecGlobalWhitelist.end(), [strName](const auto& wv) { - return wv.strConVar == StringToLower(strName); - }); + if (!g_cvarConVarWhitelistEnable.Get() || !IsConfigLoaded()) + return; - // Cannot load map overrides, only check global whitelist - if (!GetGlobals()) - return globalIt != m_vecGlobalWhitelist.end() && globalIt->bEnabled; + std::set setWhitelist; - auto mapVector = m_mapOverrides[GetGlobals()->mapname.ToCStr()]; - auto mapIt = std::find_if(mapVector.begin(), mapVector.end(), [strName](const auto& wv) { - return wv.strConVar == StringToLower(strName); - }); + for (const auto& wv : m_vecGlobalWhitelist) + if (wv.bEnabled) + setWhitelist.insert(wv.strConVar); + + auto it = m_mapOverrides.find(pszMapName); // If a map override is present, it takes priority - if (mapIt != mapVector.end()) - return mapIt->bEnabled; + if (it != m_mapOverrides.end()) + { + for (const auto& wv : it->second) + if (wv.bEnabled) + setWhitelist.insert(wv.strConVar); + else + setWhitelist.erase(wv.strConVar); + } + + CUtlSymbolTable* pWhitelistTable = addresses::CCSAddonManager_CommandWhitelist; + pWhitelistTable->RemoveAll(); + + // Modify the games table to be case-insensitive before we add our entries + static_cast(pWhitelistTable)->SetInsensitive(true); - // Or fall back to global whitelist - return globalIt != m_vecGlobalWhitelist.end() && globalIt->bEnabled; + for (const auto& strConVar : setWhitelist) + pWhitelistTable->AddString(strConVar.c_str()); } \ No newline at end of file diff --git a/src/cvarwhitelist.h b/src/cvarwhitelist.h index 8310cc56..514cabad 100644 --- a/src/cvarwhitelist.h +++ b/src/cvarwhitelist.h @@ -20,6 +20,7 @@ #pragma once #include "tier0/convar.h" +#include "tier0/utlsymboltable.h" #undef snprintf #include "vendor/nlohmann/json_fwd.hpp" @@ -33,6 +34,13 @@ struct WhitelistValue bool bEnabled; }; +// Workaround to access CUtlSymbolTable::m_bInsensitive, which is protected +class CUtlSymbolTableAccessor : public CUtlSymbolTable +{ +public: + void SetInsensitive(bool bInsensitive) { m_bInsensitive = bInsensitive; } +}; + class CConVarWhitelist { public: @@ -42,7 +50,7 @@ class CConVarWhitelist } bool LoadConfig(); - bool IsWhitelisted(std::string strName); + void ApplyToGameTable(const char* pszMapName); bool IsConfigLoaded() { return m_bConfigLoaded; }; private: diff --git a/src/detours.cpp b/src/detours.cpp index 1b292335..5f08d116 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -27,7 +27,6 @@ #include "commands.h" #include "common.h" #include "customio.h" -#include "cvarwhitelist.h" #include "detours.h" #include "engine2/serversideclient.h" #include "entities.h" @@ -87,7 +86,6 @@ KHOOK_MEMBER(CBaseModelEntity_SetModel, Detour_CBaseModelEntity_SetModel, nullpt KHOOK_MEMBER(CCSGameRules_GoToIntermission, Detour_CCSGameRules_GoToIntermission, nullptr); KHOOK_MEMBER(SetBeamOrigin, Detour_SetBeamOrigin, nullptr); KHOOK_MEMBER(SetBeamEndPos, Detour_SetBeamEndPos, nullptr); -KHOOK_FUNCTION(IsCommandWhitelisted, Detour_IsCommandWhitelisted, nullptr); KHOOK_MEMBER(CWorldRendererMgr_CreateWorld_Internal, nullptr, Detour_CWorldRendererMgr_CreateWorld_Internal_Post); std::vector& GetKHookList() @@ -695,10 +693,8 @@ KHook::Return Detour_GetFreeClient(int64_t unk1, const __m12 // Phantom client fix for (CServerSideClient* pClient : *GetClientList()) - { if (pClient && pClient->GetSignonState() < SIGNONSTATE_CONNECTED) return {KHook::Action::Supersede, pClient}; - } // Server is actually full for real return {KHook::Action::Supersede, nullptr}; @@ -923,14 +919,6 @@ KHook::Return Detour_SetBeamEndPos(CBeam* pThis, const Vector* pVecPositio return {KHook::Action::Supersede}; } -KHook::Return Detour_IsCommandWhitelisted(void* pAddonManager, const char* pszCommandName) -{ - if (!g_cvarConVarWhitelistEnable.Get() || !g_pConvarWhitelist->IsConfigLoaded()) - return {KHook::Action::Ignore}; - - return {KHook::Action::Supersede, g_pConvarWhitelist->IsWhitelisted(pszCommandName)}; -} - KHook::Return Detour_CWorldRendererMgr_CreateWorld_Internal_Post(IWorldRendererMgr* pThis, CSingleWorldRep* singleWorld) { // The world can fail to be created and the function will return nullptr. diff --git a/src/detours.h b/src/detours.h index dda7d4a3..b98b6eed 100644 --- a/src/detours.h +++ b/src/detours.h @@ -116,5 +116,4 @@ KHook::Return Detour_CBaseModelEntity_SetModel(CBaseModelEntity* pModel, c KHook::Return Detour_CCSGameRules_GoToIntermission(CCSGameRules* pThis, bool bAbortedMatch); KHook::Return Detour_SetBeamOrigin(CBeam* pThis, const Vector* pVecWorldPosition); KHook::Return Detour_SetBeamEndPos(CBeam* pThis, const Vector* pVecWorldPosition); -KHook::Return Detour_IsCommandWhitelisted(void* pAddonManager, const char* pszCommandName); KHook::Return Detour_CWorldRendererMgr_CreateWorld_Internal_Post(IWorldRendererMgr* pThis, CSingleWorldRep* pSingleWorld); diff --git a/src/gamesystem.cpp b/src/gamesystem.cpp index 1214f0cd..b79af782 100644 --- a/src/gamesystem.cpp +++ b/src/gamesystem.cpp @@ -23,7 +23,6 @@ #include "customio.h" #include "entities.h" #include "entity/cgamerules.h" -#include "gameconfig.h" #include "idlemanager.h" #include "leader.h" #include "playermanager.h" @@ -39,27 +38,14 @@ CGameSystemStaticCustomFactory* CGameSystem::sm_Factory = nullptr; // This mess is needed to get the pointer to sm_pFirst so we can insert game systems bool InitGameSystems() { - // This signature directly points to the instruction referencing sm_pFirst - uintptr_t pAddr = (uintptr_t)g_GameConfig->ResolveSignature("IGameSystem_InitAllSystems_pFirst"); + CBaseGameSystemFactory::sm_pFirst = (CBaseGameSystemFactory**)addresses::ResolveRipRelative("IGameSystem_InitAllSystems_pFirst"); - if (!pAddr) + if (!CBaseGameSystemFactory::sm_pFirst) { Panic("Failed to InitGameSystems, see warnings above.\n"); return false; } - // the opcode is 3 bytes so we skip those - pAddr += 3; - - // Grab the offset as 4 bytes - uint32 offset = *(uint32*)pAddr; - - // Go to the next instruction, which is the starting point of the relative jump - pAddr += 4; - - // Now grab our pointer - CBaseGameSystemFactory::sm_pFirst = (CBaseGameSystemFactory**)(pAddr + offset); - // And insert the game system(s) CGameSystem::sm_Factory = new CGameSystemStaticCustomFactory("CS2Fixes_GameSystem", &g_GameSystem); @@ -68,42 +54,23 @@ bool InitGameSystems() bool UnregisterGameSystem() { - // This signature directly points to the instruction referencing sm_pEventDispatcher - uintptr_t pAddr = (uintptr_t)g_GameConfig->ResolveSignature("IGameSystem_LoopPostInitAllSystems_pEventDispatcher"); + CGameSystemEventDispatcher** ppDispatchers = (CGameSystemEventDispatcher**)addresses::ResolveRipRelative("IGameSystem_LoopPostInitAllSystems_pEventDispatcher"); - if (!pAddr) + if (!ppDispatchers) { Panic("Failed to UnregisterGameSystem, see warnings above.\n"); return false; } - // the opcode is 3 bytes so we skip those - pAddr += 3; - - uint32 offset = *(uint32*)pAddr; - - // Go to the next instruction, which is the starting point of the relative jump - pAddr += 4; - - CGameSystemEventDispatcher** ppDispatchers = (CGameSystemEventDispatcher**)(pAddr + offset); - - pAddr = (uintptr_t)g_GameConfig->ResolveSignature("IGameSystem_LoopDestroyAllSystems_s_GameSystems"); + // Here the opcode is 2 bytes as it's moving a dword, not a qword, but that's the start of a vector object + CUtlVector* pGameSystems = (CUtlVector*)addresses::ResolveRipRelative("IGameSystem_LoopDestroyAllSystems_s_GameSystems", 2); - if (!pAddr) + if (!pGameSystems) { Panic("Failed to UnregisterGameSystem, see warnings above.\n"); return false; } - // Here the opcode is 2 bytes as it's moving a dword, not a qword, but that's the start of a vector object - pAddr += 2; - - offset = *(uint32*)pAddr; - - pAddr += 4; - - CUtlVector* pGameSystems = (CUtlVector*)(pAddr + offset); - auto* pDispatcher = *ppDispatchers; if (!pDispatcher || !pGameSystems) diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 4262fd85..ee4eb752 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -1982,10 +1982,8 @@ int CPlayerManager::GetOnlinePlayerCount(bool bCountBots) flLastUpdateTime = GetGlobals()->curtime; for (CServerSideClient* pClient : *GetClientList()) - { if (pClient && pClient->GetSignonState() >= SIGNONSTATE_CONNECTED && (bCountBots || !pClient->IsFakeClient())) iOnlinePlayers++; - } return iOnlinePlayers; } diff --git a/src/virtual_hooks.cpp b/src/virtual_hooks.cpp index 7f8076eb..06f13727 100644 --- a/src/virtual_hooks.cpp +++ b/src/virtual_hooks.cpp @@ -818,12 +818,10 @@ KHook::Return Hook_GetTouchingList_Post(CVPhys2World* pThis, CUtlVector unTouchLinks; for (const auto& link : *pList) - { if (link.IsUnTouching()) unTouchLinks.push_back(link); else touchingLinks.push_back(link); - } if (touchingLinks.size() <= 1) return {KHook::Action::Ignore}; From 6ccbac75bcf7631767b0599b842fa90c560661c3 Mon Sep 17 00:00:00 2001 From: cjujn <311919349+cjujn@users.noreply.github.com> Date: Tue, 20 Oct 2026 22:05:10 +0800 Subject: [PATCH 8/9] Add cs2f_spawngroup_release_manifests to stop ForceSpawn slowing down Every point_template ForceSpawn loads a new spawn group and merges it into the owner spawn group (the map's group by default). The merge moves the child's resource manifests into the owner, which keeps them until map change, so each ForceSpawn adds one manifest and later ForceSpawns get slower (0.53 ms -> 1.47 ms per call after 65k calls, nothing left alive). With the new experimental cvar enabled, the manifests a merge hands over are destroyed right away, the same way the spawn group destructor does it. ForceSpawn cost then stays flat (0.49 ms per call after 141k calls). The hook fails soft: a missing signature or offset only disables the cvar. Co-Authored-By: Claude Opus 5.5 --- AMBuilder | 1 + cfg/cs2fixes/cs2fixes.cfg | 1 + gamedata/cs2fixes.jsonc | 24 +++++ src/spawngroupfix.cpp | 180 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+) create mode 100644 src/spawngroupfix.cpp diff --git a/AMBuilder b/AMBuilder index 6abb84fb..cbf5565a 100644 --- a/AMBuilder +++ b/AMBuilder @@ -38,6 +38,7 @@ for sdk_target in MMSPlugin.sdk_targets: 'src/commands.cpp', 'src/addresses.cpp', 'src/detours.cpp', + 'src/spawngroupfix.cpp', 'src/virtual_hooks.cpp', 'src/entities.cpp', 'src/events.cpp', diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 2ed7948d..78e53f4c 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_spawngroup_release_manifests 0 // Whether to destroy the resource manifests a point_template ForceSpawn hands to the map spawn group, stops ForceSpawn getting slower over the map, 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/gamedata/cs2fixes.jsonc b/gamedata/cs2fixes.jsonc index d3e74c63..99b1e450 100644 --- a/gamedata/cs2fixes.jsonc +++ b/gamedata/cs2fixes.jsonc @@ -229,6 +229,13 @@ "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" }, + // CBaseSpawnGroup vfunc that merges a spawn group into its owner, the function with "%s: Transfering creation sequence %d to owner spawn group %s" + "CBaseSpawnGroup_MergeIntoOwner": + { + "library": "engine", + "windows": "48 89 5C 24 18 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 30 33 ED 4C 8B F2 89 6C 24 70 4C 8B F9 F6 81 68 02 00 00 01", + "linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 41 54 53 48 89 F3 48 83 EC ? F6 87 68 02 00 00 01" + }, // Return value of this function is used to determine whether "NETWORK_DISCONNECT_REJECT_SERVERFULL to %s: Cannot get free client\n" gets printed "GetFreeClient": { @@ -448,6 +455,23 @@ "windows": 37, "linux": 38 }, + // Byte offset of the resource manifest CUtlVector, the first vector CBaseSpawnGroup_MergeIntoOwner appends from the child to the owner + "CBaseSpawnGroup_ResourceManifests": + { + "windows": 552, + "linux": 552 + }, + // Byte offset of the IGameResourceService pointer, the CBaseSpawnGroup destructor calls IGameResourceService_DestroyManifest on it for each resource manifest + "CBaseSpawnGroup_ResourceService": + { + "windows": 544, + "linux": 544 + }, + "IGameResourceService_DestroyManifest": + { + "windows": 31, + "linux": 31 + }, // 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": { diff --git a/src/spawngroupfix.cpp b/src/spawngroupfix.cpp new file mode 100644 index 00000000..eadfad96 --- /dev/null +++ b/src/spawngroupfix.cpp @@ -0,0 +1,180 @@ +/** + * ============================================================================= + * 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 . + */ + +// Every point_template ForceSpawn loads a new spawn group and merges it into the template's owner +// spawn group (the map's group by default) when the spawn finishes. The merge moves the child's +// resource manifests into the owner, which keeps them until it is destroyed on map change, so the +// owner gains one manifest per ForceSpawn and every later ForceSpawn gets slower (measured 0.53 ms +// -> 1.47 ms per call after 65k calls, nothing left alive). +// +// With cs2f_spawngroup_release_manifests enabled, the manifests a merge hands to the owner are +// destroyed right away, the same way the spawn group destructor destroys them. ForceSpawn cost then +// stays flat (0.49 ms per call after 141k calls). Resources that are only referenced by those +// manifests may be unloaded, so this is opt-in. + +#include "common.h" +#include "cs2fixes.h" +#include "gameconfig.h" +#include "khook.hpp" +#include "tier0/convar.h" +#include "utils/khook_helpers.h" + +#include + +#include "tier0/memdbgon.h" + +CConVar g_cvarSpawnGroupReleaseManifests("cs2f_spawngroup_release_manifests", FCVAR_NONE, "Whether to destroy the resource manifests a point_template ForceSpawn hands to the map spawn group, stops ForceSpawn getting slower over the map, experimental", false); + +namespace +{ + // CUtlVector layout used by CBaseSpawnGroup for its resource manifest list + struct ManifestVector + { + int m_nSize; + void** m_pMemory; + int m_nAllocated; + int m_nGrowSize; + }; + + int g_iManifestsOffset = -1; + int g_iResourceServiceOffset = -1; + int g_iDestroyManifestIndex = -1; + bool g_bDisabled = false; + + // Manifest count of the owner before each (possibly nested) merge, -1 when not releasing + thread_local std::vector t_ownerManifestCounts; + + ManifestVector* GetManifests(void* pSpawnGroup) + { + return reinterpret_cast(reinterpret_cast(pSpawnGroup) + g_iManifestsOffset); + } + + void* GetResourceService(void* pSpawnGroup) + { + return *reinterpret_cast(reinterpret_cast(pSpawnGroup) + g_iResourceServiceOffset); + } + + bool IsValidVector(const ManifestVector* pVec) + { + return pVec->m_nSize >= 0 && pVec->m_nSize <= pVec->m_nAllocated && (pVec->m_nSize == 0 || pVec->m_pMemory); + } + + void Disable(const char* pszReason) + { + g_bDisabled = true; + Warning("[SpawnGroup] %s, manifest release disabled\n", pszReason); + } + + KHook::Return Hook_MergeIntoOwner(void* pChild, void* pOwner) + { + int nCount = -1; + + if (pChild && pOwner && !g_bDisabled && g_cvarSpawnGroupReleaseManifests.Get()) + { + ManifestVector* pManifests = GetManifests(pOwner); + + if (!IsValidVector(pManifests)) + Disable("Unexpected spawn group layout"); + else if (GetResourceService(pOwner)) + nCount = pManifests->m_nSize; + } + + t_ownerManifestCounts.push_back(nCount); + return {KHook::Action::Ignore}; + } + + KHook::Return Hook_MergeIntoOwner_Post(void* pChild, void* pOwner) + { + if (t_ownerManifestCounts.empty()) + return {KHook::Action::Ignore}; + + int nOldCount = t_ownerManifestCounts.back(); + t_ownerManifestCounts.pop_back(); + + if (nOldCount < 0 || g_bDisabled) + return {KHook::Action::Ignore}; + + ManifestVector* pManifests = GetManifests(pOwner); + void* pService = GetResourceService(pOwner); + + if (!IsValidVector(pManifests) || pManifests->m_nSize < nOldCount || !pService) + { + Disable("Owner manifest list changed unexpectedly during merge"); + return {KHook::Action::Ignore}; + } + + using DestroyManifestFn = void (*)(void*, void*); + auto pfnDestroyManifest = (*reinterpret_cast(pService))[g_iDestroyManifestIndex]; + int nNewCount = pManifests->m_nSize; + + // Shrink first so the owner never points at a destroyed manifest + pManifests->m_nSize = nOldCount; + + for (int i = nOldCount; i < nNewCount; i++) + { + if (pManifests->m_pMemory[i]) + pfnDestroyManifest(pService, pManifests->m_pMemory[i]); + + pManifests->m_pMemory[i] = nullptr; + } + + return {KHook::Action::Ignore}; + } + + // Unlike CKHookFunction, a missing signature or offset only disables this feature instead of failing the plugin load + class CMergeIntoOwnerHook : public CKHookBase + { + public: + CMergeIntoOwnerHook() : + m_hook(Hook_MergeIntoOwner, Hook_MergeIntoOwner_Post) + { + GetKHookList().push_back(this); + } + + virtual void Configure() override + { + g_iManifestsOffset = g_GameConfig->GetOffset("CBaseSpawnGroup_ResourceManifests"); + g_iResourceServiceOffset = g_GameConfig->GetOffset("CBaseSpawnGroup_ResourceService"); + g_iDestroyManifestIndex = g_GameConfig->GetOffset("IGameResourceService_DestroyManifest"); + + if (g_iManifestsOffset < 0 || g_iResourceServiceOffset < 0 || g_iDestroyManifestIndex < 0) + { + Warning("[SpawnGroup] Missing spawn group offsets, cs2f_spawngroup_release_manifests is unavailable\n"); + return; + } + + auto address = g_GameConfig->ResolveSignature("CBaseSpawnGroup_MergeIntoOwner"); + + if (!address) + { + Warning("[SpawnGroup] Failed to find CBaseSpawnGroup_MergeIntoOwner, cs2f_spawngroup_release_manifests is unavailable\n"); + return; + } + + m_hook.Configure(address); + + Message("Hooked CBaseSpawnGroup_MergeIntoOwner at 0x%p\n", address); + } + + private: + KHook::Function m_hook; + }; + + CMergeIntoOwnerHook g_hookMergeIntoOwner; +} // namespace From 8a03d6203311a892e15090338a668f0864a3db2d Mon Sep 17 00:00:00 2001 From: cjujn <311919349+cjujn@users.noreply.github.com> Date: Tue, 20 Oct 2026 22:05:10 +0800 Subject: [PATCH 9/9] Rename cvar to cs2f_fix_forcespawn_slowdown Name it after the symptom server operators see, matching cs2f_fix_game_bans. Co-Authored-By: Claude Opus 5.5 --- cfg/cs2fixes/cs2fixes.cfg | 2 +- src/spawngroupfix.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 78e53f4c..69f0af31 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -28,7 +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_spawngroup_release_manifests 0 // Whether to destroy the resource manifests a point_template ForceSpawn hands to the map spawn group, stops ForceSpawn getting slower over the map, experimental +cs2f_fix_forcespawn_slowdown 0 // Whether to fix point_template ForceSpawn getting slower over the course of a map by releasing the resource manifests each spawn leaves on the map spawn group, 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/spawngroupfix.cpp b/src/spawngroupfix.cpp index eadfad96..a0e13005 100644 --- a/src/spawngroupfix.cpp +++ b/src/spawngroupfix.cpp @@ -23,7 +23,7 @@ // owner gains one manifest per ForceSpawn and every later ForceSpawn gets slower (measured 0.53 ms // -> 1.47 ms per call after 65k calls, nothing left alive). // -// With cs2f_spawngroup_release_manifests enabled, the manifests a merge hands to the owner are +// With cs2f_fix_forcespawn_slowdown enabled, the manifests a merge hands to the owner are // destroyed right away, the same way the spawn group destructor destroys them. ForceSpawn cost then // stays flat (0.49 ms per call after 141k calls). Resources that are only referenced by those // manifests may be unloaded, so this is opt-in. @@ -39,7 +39,7 @@ #include "tier0/memdbgon.h" -CConVar g_cvarSpawnGroupReleaseManifests("cs2f_spawngroup_release_manifests", FCVAR_NONE, "Whether to destroy the resource manifests a point_template ForceSpawn hands to the map spawn group, stops ForceSpawn getting slower over the map, experimental", false); +CConVar g_cvarFixForceSpawnSlowdown("cs2f_fix_forcespawn_slowdown", FCVAR_NONE, "Whether to fix point_template ForceSpawn getting slower over the course of a map by releasing the resource manifests each spawn leaves on the map spawn group, experimental", false); namespace { @@ -85,7 +85,7 @@ namespace { int nCount = -1; - if (pChild && pOwner && !g_bDisabled && g_cvarSpawnGroupReleaseManifests.Get()) + if (pChild && pOwner && !g_bDisabled && g_cvarFixForceSpawnSlowdown.Get()) { ManifestVector* pManifests = GetManifests(pOwner); @@ -155,7 +155,7 @@ namespace if (g_iManifestsOffset < 0 || g_iResourceServiceOffset < 0 || g_iDestroyManifestIndex < 0) { - Warning("[SpawnGroup] Missing spawn group offsets, cs2f_spawngroup_release_manifests is unavailable\n"); + Warning("[SpawnGroup] Missing spawn group offsets, cs2f_fix_forcespawn_slowdown is unavailable\n"); return; } @@ -163,7 +163,7 @@ namespace if (!address) { - Warning("[SpawnGroup] Failed to find CBaseSpawnGroup_MergeIntoOwner, cs2f_spawngroup_release_manifests is unavailable\n"); + Warning("[SpawnGroup] Failed to find CBaseSpawnGroup_MergeIntoOwner, cs2f_fix_forcespawn_slowdown is unavailable\n"); return; }