From ae485c311541bb0fa609e5a9a33e0fdf1595fd56 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Mon, 8 Mar 2021 17:42:32 -0500 Subject: [PATCH] Add A2S_Rules fix for CS:GO to CStrike extension. (#614) * Add A2S_Rules fix for CS:GO to CStrike extension. * Dont force set the cvar. Add checks before patching. * Remove incorrect and useless check. * Remove checking value as it is in the signature. * Update build script changes to AMBuild 2.1 API to fix build. * Fix bad check and ConVarRef being resolved too early. * Whoops. This line is kinda important. Got nuked when refactoring. * Remove unused variable. * Updatet gamedata. * Switch to "Addresses" gamedata lookup * Add linux64 gamedata * Fix mac build Co-authored-by: Ruben Gonzalez Co-authored-by: Peace-Maker --- extensions/cstrike/AMBuilder | 39 +++- extensions/cstrike/extension.cpp | 14 ++ extensions/cstrike/rulesfix.cpp | 232 ++++++++++++++++++++++++ extensions/cstrike/rulesfix.h | 52 ++++++ extensions/cstrike/smsdk_config.h | 4 +- gamedata/sm-cstrike.games/game.csgo.txt | 39 ++++ 6 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 extensions/cstrike/rulesfix.cpp create mode 100644 extensions/cstrike/rulesfix.h diff --git a/extensions/cstrike/AMBuilder b/extensions/cstrike/AMBuilder index 9cb95ccc..3ecf07ff 100644 --- a/extensions/cstrike/AMBuilder +++ b/extensions/cstrike/AMBuilder @@ -24,11 +24,46 @@ for sdk_name in ['css', 'csgo']: if sdk_name not in SM.sdks: continue sdk = SM.sdks[sdk_name] + + if sdk_name == 'csgo': + project.sources += ['rulesfix.cpp'] + for cxx in builder.targets: if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]: continue - cxx.defines += ['HAVE_STRING_H']; - SM.HL2ExtConfig(project, builder, cxx, 'game.cstrike.ext.' + sdk.ext, sdk) + cxx.defines += ['HAVE_STRING_H'] + binary = SM.HL2ExtConfig(project, builder, cxx, 'game.cstrike.ext.' + sdk.ext, sdk) + if sdk_name == 'csgo': + compiler = binary.compiler + compiler.cxxincludes += [os.path.join(sdk.path, 'public', 'steam')] + compiler.defines += ['VERSION_SAFE_STEAM_API_INTERFACES'] + + library_name = '' + if cxx.target.platform == 'windows': + compiler.linkflags += [os.path.join(sdk.path, 'lib', 'public', 'steam_api.lib')] + elif cxx.target.platform == 'linux': + library_name = 'libsteam_api.so' + if cxx.target.arch == 'x86_64': + source_path = os.path.join(sdk.path, 'lib', 'linux64') + else: + source_path = os.path.join(sdk.path, 'lib', 'linux') + elif cxx.target.platform == 'mac': + library_name = 'libsteam_api.dylib' + if cxx.target.arch == 'x86_64': + source_path = os.path.join(sdk.path, 'lib', 'osx64') + else: + source_path = os.path.join(sdk.path, 'lib', 'mac') + + if library_name: + source_path = os.path.join(source_path, library_name) + output_path = os.path.join(binary.localFolder, library_name) + + # Ensure the output path exists. + builder.AddFolder(binary.localFolder) + output = builder.AddSymlink(source_path, output_path) + + compiler.weaklinkdeps += [output] + compiler.linkflags[0:0] = [library_name] SM.extensions += builder.Add(project) diff --git a/extensions/cstrike/extension.cpp b/extensions/cstrike/extension.cpp index 0e68f5c8..c51858a8 100644 --- a/extensions/cstrike/extension.cpp +++ b/extensions/cstrike/extension.cpp @@ -36,6 +36,9 @@ #include "iplayerinfo.h" #include "ISDKTools.h" #include "forwards.h" +#if SOURCE_ENGINE == SE_CSGO +#include "rulesfix.h" +#endif #include "util_cstrike.h" /** @@ -88,6 +91,10 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late) playerhelpers->RegisterCommandTargetProcessor(this); +#if SOURCE_ENGINE == SE_CSGO + rulesfix.OnLoad(); +#endif + CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf); g_pHandleBuyForward = forwards->CreateForward("CS_OnBuyCommand", ET_Event, 2, NULL, Param_Cell, Param_String); @@ -110,6 +117,12 @@ bool CStrike::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); gpGlobals = ismm->GetCGlobals(); +#if SOURCE_ENGINE == SE_CSGO + ICvar *icvar; + GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION); + g_pCVar = icvar; +#endif + return true; } @@ -153,6 +166,7 @@ void CStrike::SDK_OnUnload() forwards->ReleaseForward(g_pCSWeaponDropForward); #if SOURCE_ENGINE == SE_CSGO + rulesfix.OnUnload(); ClearHashMaps(); #endif } diff --git a/extensions/cstrike/rulesfix.cpp b/extensions/cstrike/rulesfix.cpp new file mode 100644 index 00000000..eb114f62 --- /dev/null +++ b/extensions/cstrike/rulesfix.cpp @@ -0,0 +1,232 @@ +/** +* vim: set ts=4 : +* ============================================================================= +* SourceMod Counter-Strike:Source Extension +* Copyright (C) 2017 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* 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 . +* +* As a special exception, AlliedModders LLC gives you permission to link the +* code of this program (as well as its derivative works) to "Half-Life 2," the +* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software +* by the Valve Corporation. You must obey the GNU General Public License in +* all respects for all other code used. Additionally, AlliedModders LLC grants +* this exception to all derivative works. AlliedModders LLC defines further +* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), +* or . +* +* Version: $Id$ +*/ + +#include "rulesfix.h" +#include "extension.h" +#include + +// Grab the convar ref +ConVar *host_rules_show = nullptr; +bool bPatched = false; + +RulesFix rulesfix; + +SH_DECL_HOOK1_void(IServerGameDLL, GameServerSteamAPIActivated, SH_NOATTRIB, 0, bool); + +RulesFix::RulesFix() : + m_OnSteamServersConnected(this, &RulesFix::OnSteamServersConnected) +{ +} + +void SetMTUMax(int iValue) +{ + static int iOriginalValue = -1; + static int *m_pMaxMTU = nullptr; + + //If we never changed skip resetting + if (iOriginalValue == -1 && iValue == -1) + return; + + if (m_pMaxMTU == nullptr) + { + if (!g_pGameConf->GetAddress("MaxMTU", (void **)&m_pMaxMTU)) + { + g_pSM->LogMessage(myself, "[CStrike] Failed to locate NET_SendPacket signature."); + return; + } + + SourceHook::SetMemAccess(m_pMaxMTU, sizeof(int), SH_MEM_READ | SH_MEM_WRITE | SH_MEM_EXEC); + + iOriginalValue = *m_pMaxMTU; + } + + if (iValue == -1) + *m_pMaxMTU = iOriginalValue; + else + *m_pMaxMTU = iValue; +} + +void RulesFix::OnLoad() +{ + host_rules_show = g_pCVar->FindVar("host_rules_show"); + if (host_rules_show) + { + // Default to enabled. Explicit disable via cfg will still be obeyed. + host_rules_show->SetValue(true); + + SetMTUMax(5000); + bPatched = true; + } + + SH_ADD_HOOK(IServerGameDLL, GameServerSteamAPIActivated, gamedll, SH_MEMBER(this, &RulesFix::Hook_GameServerSteamAPIActivated), true); +} + +void RulesFix::OnUnload() +{ + SetMTUMax(-1); + SH_REMOVE_HOOK(IServerGameDLL, GameServerSteamAPIActivated, gamedll, SH_MEMBER(this, &RulesFix::Hook_GameServerSteamAPIActivated), true); +} + +void NotifyAllCVars() +{ + ICvar::Iterator iter(g_pCVar); + for (iter.SetFirst(); iter.IsValid(); iter.Next()) + { + ConCommandBase *cmd = iter.Get(); + if (!cmd->IsCommand() && cmd->IsFlagSet(FCVAR_NOTIFY)) + { + rulesfix.OnNotifyConVarChanged((ConVar *)cmd); + } + } +} + +void RulesFix::OnSteamServersConnected(SteamServersConnected_t *) +{ + // The engine clears all after the Steam interfaces become available after they've been gone. + NotifyAllCVars(); +} + +static void OnConVarChanged(IConVar *var, const char *pOldValue, float flOldValue) +{ + if (host_rules_show && var == host_rules_show) + { + if (host_rules_show->GetBool()) + { + if (!bPatched) + { + SetMTUMax(5000); + bPatched = true; + NotifyAllCVars(); + } + } + else + { + if (bPatched) + { + SetMTUMax(-1); + bPatched = false; + } + } + } + + if (var->IsFlagSet(FCVAR_NOTIFY)) + { + rulesfix.OnNotifyConVarChanged((ConVar *)var); + } +} + +void RulesFix::OnNotifyConVarChanged(ConVar *pVar) +{ + if (!bPatched) + return; + + if (m_Steam.SteamMasterServerUpdater()) + { + if (pVar->IsFlagSet(FCVAR_PROTECTED)) + { + if (!pVar->GetString()[0]) + { + m_Steam.SteamMasterServerUpdater()->SetKeyValue(pVar->GetName(), "0"); + } + else + { + m_Steam.SteamMasterServerUpdater()->SetKeyValue(pVar->GetName(), "1"); + } + } + else + { + m_Steam.SteamMasterServerUpdater()->SetKeyValue(pVar->GetName(), pVar->GetString()); + } + } +} + +void RulesFix::Hook_GameServerSteamAPIActivated(bool bActivated) +{ + if (bActivated) + { + FixSteam(); + m_Steam.Init(); + + g_pCVar->InstallGlobalChangeCallback(OnConVarChanged); + OnSteamServersConnected(nullptr); + } + else + { + g_pCVar->RemoveGlobalChangeCallback(OnConVarChanged); + m_Steam.Clear(); + } +} + +void RulesFix::FixSteam() +{ + if (!g_pSteamClientGameServer) + { + void *(*pGSInternalCreateAddress)(const char *) = nullptr; + void *(*pInternalCreateAddress)(const char *) = nullptr; + + // CS:GO currently uses the old name, but will use the new name when they update to a + // newer Steamworks SDK. Stay compatible. + const char *pGSInternalFuncName = "SteamGameServerInternal_CreateInterface"; + const char *pInternalFuncName = "SteamInternal_CreateInterface"; + + ILibrary *pLibrary = libsys->OpenLibrary( +#if defined ( PLATFORM_WINDOWS ) + "steam_api.dll" +#elif defined( PLATFORM_LINUX ) + "libsteam_api.so" +#elif defined( PLATFORM_APPLE ) + "libsteam_api.dylib" +#else +#error Unsupported platform +#endif + , nullptr, 0); + if (pLibrary != nullptr) + { + if (pGSInternalCreateAddress == nullptr) + { + pGSInternalCreateAddress = reinterpret_cast(pLibrary->GetSymbolAddress(pGSInternalFuncName)); + } + + if (pInternalCreateAddress == nullptr) + { + pInternalCreateAddress = reinterpret_cast(pLibrary->GetSymbolAddress(pInternalFuncName)); + } + + pLibrary->CloseLibrary(); + } + + if (pGSInternalCreateAddress != nullptr) + g_pSteamClientGameServer = reinterpret_cast((*pGSInternalCreateAddress)(STEAMCLIENT_INTERFACE_VERSION)); + + if (g_pSteamClientGameServer == nullptr && pInternalCreateAddress != nullptr) + g_pSteamClientGameServer = reinterpret_cast((*pInternalCreateAddress)(STEAMCLIENT_INTERFACE_VERSION)); + } +} diff --git a/extensions/cstrike/rulesfix.h b/extensions/cstrike/rulesfix.h new file mode 100644 index 00000000..e83c65d7 --- /dev/null +++ b/extensions/cstrike/rulesfix.h @@ -0,0 +1,52 @@ +/** +* vim: set ts=4 : +* ============================================================================= +* SourceMod Counter-Strike:Source Extension +* Copyright (C) 2017 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* 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 . +* +* As a special exception, AlliedModders LLC gives you permission to link the +* code of this program (as well as its derivative works) to "Half-Life 2," the +* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software +* by the Valve Corporation. You must obey the GNU General Public License in +* all respects for all other code used. Additionally, AlliedModders LLC grants +* this exception to all derivative works. AlliedModders LLC defines further +* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), +* or . +* +* Version: $Id$ +*/ + +#pragma once + +#include +class ConVar; + +class RulesFix +{ +public: + RulesFix(); + void OnLoad(); + void OnUnload(); + void OnNotifyConVarChanged(ConVar *pVar); + void Hook_GameServerSteamAPIActivated(bool bActivated); +private: + void FixSteam(); +private: + CSteamGameServerAPIContext m_Steam; + STEAM_GAMESERVER_CALLBACK(RulesFix, OnSteamServersConnected, SteamServersConnected_t, m_OnSteamServersConnected); +}; + +extern RulesFix rulesfix; diff --git a/extensions/cstrike/smsdk_config.h b/extensions/cstrike/smsdk_config.h index 3105fb77..617a2c53 100644 --- a/extensions/cstrike/smsdk_config.h +++ b/extensions/cstrike/smsdk_config.h @@ -68,7 +68,9 @@ #define SMEXT_ENABLE_GAMEHELPERS #define SMEXT_ENABLE_TIMERSYS //#define SMEXT_ENABLE_THREADER -//#define SMEXT_ENABLE_LIBSYS +#if SOURCE_ENGINE == SE_CSGO +#define SMEXT_ENABLE_LIBSYS +#endif #define SMEXT_ENABLE_USERMSGS #define SMEXT_ENABLE_PLUGINSYS diff --git a/gamedata/sm-cstrike.games/game.csgo.txt b/gamedata/sm-cstrike.games/game.csgo.txt index 3424ecad..69d5cdf8 100644 --- a/gamedata/sm-cstrike.games/game.csgo.txt +++ b/gamedata/sm-cstrike.games/game.csgo.txt @@ -264,4 +264,43 @@ } } } + + "#default" + { + "Addresses" + { + // Offset from NET_SendPacket sig to MTU + "MaxMTU" + { + "windows" + { + "signature" "NET_SendPacket" + "offset" "6" + } + "linux" + { + "signature" "NET_SendPacket" + "offset" "5" + } + "linux64" + { + "signature" "NET_SendPacket" + "offset" "4" + } + } + } + "Signatures" + { + // This isn't the start of the function, but closer to where we want to patch, including the exact bytes we will replace + "NET_SendPacket" + { + "library" "engine" + // "[NET] Cannot send %d-byte packet to %s. MTU is %u. %02x %02x %02x %02x %02x\n" + "windows" "\x89\x4C\x24\x14\x81\xFF\xB0\x04\x00\x00\x7E" + // _Z14NET_SendPacketP11INetChanneliRK10ns_addressPKhiP8bf_writebj + "linux" "\x8B\x7D\x10\x81\xFE\xB0\x04\x00\x00\x0F" + "linux64" "\x31\xC0\x81\xF9\xB0\x04\x00\x00\x0F" + } + } + } }