From 2c02e7bc6a8055c5950a5ec8cb2fb40c6513436b Mon Sep 17 00:00:00 2001 From: Glacir <122596880+Glacir@users.noreply.github.com> Date: Mon, 30 Jan 2023 18:44:16 +0800 Subject: Format content of `enabledmods.json` (#406) Format enabledmods.json --- NorthstarDLL/mods/modmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NorthstarDLL/mods/modmanager.cpp b/NorthstarDLL/mods/modmanager.cpp index 6310b7ec..a47aa854 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -11,7 +11,7 @@ #include "rapidjson/error/en.h" #include "rapidjson/document.h" #include "rapidjson/ostreamwrapper.h" -#include "rapidjson/writer.h" +#include "rapidjson/prettywriter.h" #include #include #include @@ -750,7 +750,7 @@ void ModManager::UnloadMods() std::ofstream writeStream(GetNorthstarPrefix() + "/enabledmods.json"); rapidjson::OStreamWrapper writeStreamWrapper(writeStream); - rapidjson::Writer writer(writeStreamWrapper); + rapidjson::PrettyWriter writer(writeStreamWrapper); m_EnabledModsCfg.Accept(writer); // do we need to dealloc individual entries in m_loadedMods? idk, rework -- cgit v1.2.3 From d418217e0ac6ada2217d5e5171f6baa3707380c9 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Mon, 30 Jan 2023 11:44:37 +0100 Subject: feat: Remote mods directory (#403) * feat: create remote mod directory * feat: look for mods in remote mods directory --- NorthstarDLL/mods/modmanager.cpp | 15 ++++++++++++--- NorthstarDLL/mods/modmanager.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/NorthstarDLL/mods/modmanager.cpp b/NorthstarDLL/mods/modmanager.cpp index a47aa854..38966236 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -354,6 +354,7 @@ void ModManager::LoadMods() // ensure dirs exist fs::remove_all(GetCompiledAssetsPath()); fs::create_directories(GetModFolderPath()); + fs::create_directories(GetRemoteModFolderPath()); m_DependencyConstants.clear(); @@ -374,9 +375,13 @@ void ModManager::LoadMods() } // get mod directories - for (fs::directory_entry dir : fs::directory_iterator(GetModFolderPath())) - if (fs::exists(dir.path() / "mod.json")) - modDirs.push_back(dir.path()); + std::filesystem::directory_iterator classicModsDir = fs::directory_iterator(GetModFolderPath()); + std::filesystem::directory_iterator remoteModsDir = fs::directory_iterator(GetRemoteModFolderPath()); + + for (std::filesystem::directory_iterator modIterator : {classicModsDir, remoteModsDir}) + for (fs::directory_entry dir : modIterator) + if (fs::exists(dir.path() / "mod.json")) + modDirs.push_back(dir.path()); for (fs::path modDir : modDirs) { @@ -805,6 +810,10 @@ fs::path GetModFolderPath() { return fs::path(GetNorthstarPrefix() + MOD_FOLDER_SUFFIX); } +fs::path GetRemoteModFolderPath() +{ + return fs::path(GetNorthstarPrefix() + REMOTE_MOD_FOLDER_SUFFIX); +} fs::path GetCompiledAssetsPath() { return fs::path(GetNorthstarPrefix() + COMPILED_ASSETS_SUFFIX); diff --git a/NorthstarDLL/mods/modmanager.h b/NorthstarDLL/mods/modmanager.h index ded6ff06..c2335d09 100644 --- a/NorthstarDLL/mods/modmanager.h +++ b/NorthstarDLL/mods/modmanager.h @@ -161,6 +161,7 @@ class ModManager }; fs::path GetModFolderPath(); +fs::path GetRemoteModFolderPath(); fs::path GetCompiledAssetsPath(); extern ModManager* g_pModManager; -- cgit v1.2.3 From f7b7de8a584b877b9bf05fe63a0b0f91c7a5e944 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Wed, 1 Feb 2023 20:25:45 +0000 Subject: Allow `launchplaylist` to be used to start dedicated servers (#409) allow launchplaylist to be used to start dedicated servers --- NorthstarDLL/dedicated/dedicated.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NorthstarDLL/dedicated/dedicated.cpp b/NorthstarDLL/dedicated/dedicated.cpp index 33a3f034..8f6f8fe6 100644 --- a/NorthstarDLL/dedicated/dedicated.cpp +++ b/NorthstarDLL/dedicated/dedicated.cpp @@ -48,9 +48,9 @@ void RunServer(CDedicatedExports* dedicated) // initialise engine g_pEngine->Frame(); - // add +map if not present + // add +map if no map loading command is present // don't manually execute this from cbuf as users may have it in their startup args anyway, easier just to run from stuffcmds if present - if (!Tier0::CommandLine()->CheckParm("+map")) + if (!Tier0::CommandLine()->CheckParm("+map") && !Tier0::CommandLine()->CheckParm("+launchplaylist")) Tier0::CommandLine()->AppendParm("+map", g_pCVar->FindVar("match_defaultMap")->GetString()); // re-run commandline -- cgit v1.2.3 From 31a05c35e60b844cf806b146a4889f79272ed749 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 6 Feb 2023 00:25:06 +0000 Subject: Flush loggers properly on dedicated server shutdown (#413) flush loggers properly on dedicated server shutdown --- NorthstarDLL/dedicated/dedicated.cpp | 3 +++ NorthstarDLL/logging/crashhandler.cpp | 2 ++ NorthstarDLL/logging/logging.cpp | 8 ++++++++ NorthstarDLL/logging/logging.h | 2 ++ 4 files changed, 15 insertions(+) diff --git a/NorthstarDLL/dedicated/dedicated.cpp b/NorthstarDLL/dedicated/dedicated.cpp index 8f6f8fe6..3d7d756c 100644 --- a/NorthstarDLL/dedicated/dedicated.cpp +++ b/NorthstarDLL/dedicated/dedicated.cpp @@ -278,7 +278,10 @@ void, __fastcall, (void* sqvm)) // atm, this will crash if not aborted, so this just closes more gracefully static ConVar* Cvar_fatal_script_errors = g_pCVar->FindVar("fatal_script_errors"); if (Cvar_fatal_script_errors->GetBool()) + { + NS::log::FlushLoggers(); abort(); + } } ON_DLL_LOAD_DEDI("server.dll", DedicatedServerGameDLL, (CModule module)) diff --git a/NorthstarDLL/logging/crashhandler.cpp b/NorthstarDLL/logging/crashhandler.cpp index d4a54169..1e9bf4b3 100644 --- a/NorthstarDLL/logging/crashhandler.cpp +++ b/NorthstarDLL/logging/crashhandler.cpp @@ -72,6 +72,8 @@ void PrintExceptionLog(ExceptionLog& exc) "Northstar has crashed! Crash info can be found in R2Northstar/logs", "Northstar has crashed!", MB_ICONERROR | MB_OK | MB_SYSTEMMODAL); + + NS::log::FlushLoggers(); } std::string GetExceptionName(ExceptionLog& exc) diff --git a/NorthstarDLL/logging/logging.cpp b/NorthstarDLL/logging/logging.cpp index 6bb57170..8b906911 100644 --- a/NorthstarDLL/logging/logging.cpp +++ b/NorthstarDLL/logging/logging.cpp @@ -203,3 +203,11 @@ void InitialiseLogging() loggers.push_back(NS::log::rpak); loggers.push_back(NS::log::echo); } + +void NS::log::FlushLoggers() +{ + for (auto& logger : loggers) + logger->flush(); + + spdlog::default_logger()->flush(); +} diff --git a/NorthstarDLL/logging/logging.h b/NorthstarDLL/logging/logging.h index b710915e..2cccdde6 100644 --- a/NorthstarDLL/logging/logging.h +++ b/NorthstarDLL/logging/logging.h @@ -100,6 +100,8 @@ namespace NS::log extern std::shared_ptr echo; extern std::shared_ptr NORTHSTAR; + + void FlushLoggers(); }; // namespace NS::log void RegisterCustomSink(std::shared_ptr sink); -- cgit v1.2.3 From b77baa4d09dae917c3fc9f9fc7d6b37c8d3c5205 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 7 Feb 2023 01:02:30 +0000 Subject: Do not load streaming files on dedicated server (#412) dont load streaming files on dedicated server --- NorthstarDLL/core/filesystem/rpakfilesystem.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NorthstarDLL/core/filesystem/rpakfilesystem.cpp b/NorthstarDLL/core/filesystem/rpakfilesystem.cpp index b46218e0..c3463781 100644 --- a/NorthstarDLL/core/filesystem/rpakfilesystem.cpp +++ b/NorthstarDLL/core/filesystem/rpakfilesystem.cpp @@ -267,6 +267,9 @@ void*, __fastcall, (const char* pPath, void* pCallback)) if (path.extension() == ".stbsp") { + if (IsDedicatedServer()) + return nullptr; + NS::log::rpak->info("LoadStreamBsp: {}", filename.string()); // resolve modded stbsp path so we can load mod stbsps @@ -279,6 +282,9 @@ void*, __fastcall, (const char* pPath, void* pCallback)) } else if (path.extension() == ".starpak") { + if (IsDedicatedServer()) + return nullptr; + // code for this is mostly stolen from above // unfortunately I can't find a way to get the rpak that is causing this function call, so I have to -- cgit v1.2.3 From b61ed18a86ddd2d7ab0e80992859750a49a9c4f6 Mon Sep 17 00:00:00 2001 From: Erlite Date: Thu, 9 Feb 2023 01:44:44 +0100 Subject: Add Destroy callback for squirrel scripts. (#383) * Add Destroy callback for squirrel scripts. * Switch _call() to Call() --- NorthstarDLL/mods/modmanager.cpp | 9 +++++++++ NorthstarDLL/mods/modmanager.h | 2 ++ NorthstarDLL/squirrel/squirrel.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/NorthstarDLL/mods/modmanager.cpp b/NorthstarDLL/mods/modmanager.cpp index 38966236..e37df6e5 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -198,6 +198,9 @@ Mod::Mod(fs::path modDir, char* jsonBuf) if (scriptObj["ServerCallback"].HasMember("After") && scriptObj["ServerCallback"]["After"].IsString()) callback.AfterCallback = scriptObj["ServerCallback"]["After"].GetString(); + if (scriptObj["ServerCallback"].HasMember("Destroy") && scriptObj["ServerCallback"]["Destroy"].IsString()) + callback.DestroyCallback = scriptObj["ServerCallback"]["Destroy"].GetString(); + script.Callbacks.push_back(callback); } @@ -212,6 +215,9 @@ Mod::Mod(fs::path modDir, char* jsonBuf) if (scriptObj["ClientCallback"].HasMember("After") && scriptObj["ClientCallback"]["After"].IsString()) callback.AfterCallback = scriptObj["ClientCallback"]["After"].GetString(); + if (scriptObj["ClientCallback"].HasMember("Destroy") && scriptObj["ClientCallback"]["Destroy"].IsString()) + callback.DestroyCallback = scriptObj["ClientCallback"]["Destroy"].GetString(); + script.Callbacks.push_back(callback); } @@ -226,6 +232,9 @@ Mod::Mod(fs::path modDir, char* jsonBuf) if (scriptObj["UICallback"].HasMember("After") && scriptObj["UICallback"]["After"].IsString()) callback.AfterCallback = scriptObj["UICallback"]["After"].GetString(); + if (scriptObj["UICallback"].HasMember("Destroy") && scriptObj["UICallback"]["Destroy"].IsString()) + callback.DestroyCallback = scriptObj["UICallback"]["Destroy"].GetString(); + script.Callbacks.push_back(callback); } diff --git a/NorthstarDLL/mods/modmanager.h b/NorthstarDLL/mods/modmanager.h index c2335d09..369eb07b 100644 --- a/NorthstarDLL/mods/modmanager.h +++ b/NorthstarDLL/mods/modmanager.h @@ -41,6 +41,8 @@ struct ModScriptCallback std::string BeforeCallback; // called after the codecallback has finished executing std::string AfterCallback; + // called right before the vm is destroyed. + std::string DestroyCallback; }; struct ModScript diff --git a/NorthstarDLL/squirrel/squirrel.cpp b/NorthstarDLL/squirrel/squirrel.cpp index 4771bf3f..25fb90d5 100644 --- a/NorthstarDLL/squirrel/squirrel.cpp +++ b/NorthstarDLL/squirrel/squirrel.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "squirrel.h" +#include "logging/logging.h" #include "core/convar/concommand.h" #include "mods/modmanager.h" #include "dedicated/dedicated.h" @@ -212,7 +213,34 @@ template void SquirrelManager::VMCreated(CSquir template void SquirrelManager::VMDestroyed() { + // Call all registered mod Destroy callbacks. + if (g_pModManager) + { + NS::log::squirrel_logger()->info("Calling Destroy callbacks for all loaded mods."); + + for (const Mod& loadedMod : g_pModManager->m_LoadedMods) + { + for (const ModScript& script : loadedMod.Scripts) + { + for (const ModScriptCallback& callback : script.Callbacks) + { + if (callback.Context != context || callback.DestroyCallback.length() == 0) + { + continue; + } + + Call(callback.DestroyCallback.c_str()); + NS::log::squirrel_logger()->info("Executed Destroy callback {}.", callback.DestroyCallback); + } + } + } + } + + // Discard the previous vm and delete the message buffer. m_pSQVM = nullptr; + + delete g_pSquirrel->messageBuffer; + g_pSquirrel->messageBuffer = nullptr; } template void SquirrelManager::ExecuteCode(const char* pCode) -- cgit v1.2.3 From 95b41b6f8cc612953eafd7f8b6b40124e1590bc7 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 12 Feb 2023 21:15:00 +0000 Subject: Add `CGlobals` class and `g_pGlobals`, and update code to support (#411) * add CGlobals class and g_pGlobals, and update scripts to support * don't automatically enable antispeedhack (oops) * add dedicated.cpp * format * bad push oops * reformat again --- NorthstarDLL/dedicated/dedicated.cpp | 7 +-- NorthstarDLL/engine/r2engine.cpp | 4 ++ NorthstarDLL/engine/r2engine.h | 60 +++++++++++++++++++++++ NorthstarDLL/engine/runframe.cpp | 2 + NorthstarDLL/server/auth/bansystem.cpp | 3 +- NorthstarDLL/server/auth/serverauthentication.cpp | 3 +- NorthstarDLL/server/buildainfile.cpp | 10 ++-- NorthstarDLL/shared/exploit_fixes/ns_limits.cpp | 44 +++++++++-------- NorthstarDLL/shared/keyvalues.cpp | 19 ++++--- NorthstarDLL/shared/playlist.cpp | 3 +- NorthstarDLL/util/printmaps.cpp | 4 +- 11 files changed, 114 insertions(+), 45 deletions(-) diff --git a/NorthstarDLL/dedicated/dedicated.cpp b/NorthstarDLL/dedicated/dedicated.cpp index 3d7d756c..e58900b7 100644 --- a/NorthstarDLL/dedicated/dedicated.cpp +++ b/NorthstarDLL/dedicated/dedicated.cpp @@ -57,9 +57,6 @@ void RunServer(CDedicatedExports* dedicated) Cbuf_AddText(Cbuf_GetCurrentPlayer(), "stuffcmds", cmd_source_t::kCommandSrcCode); Cbuf_Execute(); - // get tickinterval - ConVar* Cvar_base_tickinterval_mp = g_pCVar->FindVar("base_tickinterval_mp"); - // main loop double frameTitle = 0; while (g_pEngine->m_nQuitting == EngineQuitState::QUIT_NOTQUITTING) @@ -67,8 +64,8 @@ void RunServer(CDedicatedExports* dedicated) double frameStart = Tier0::Plat_FloatTime(); g_pEngine->Frame(); - std::this_thread::sleep_for(std::chrono::duration>( - Cvar_base_tickinterval_mp->GetFloat() - fmin(Tier0::Plat_FloatTime() - frameStart, 0.25))); + std::this_thread::sleep_for( + std::chrono::duration>(g_pGlobals->m_flTickInterval - fmin(Tier0::Plat_FloatTime() - frameStart, 0.25))); } } diff --git a/NorthstarDLL/engine/r2engine.cpp b/NorthstarDLL/engine/r2engine.cpp index 22884a73..eaa392c8 100644 --- a/NorthstarDLL/engine/r2engine.cpp +++ b/NorthstarDLL/engine/r2engine.cpp @@ -21,6 +21,8 @@ namespace R2 char* g_pModName = nullptr; // we cant set this up here atm since we dont have an offset to it in engine, instead we store it in IsRespawnMod + + CGlobalVars* g_pGlobals; } // namespace R2 ON_DLL_LOAD("engine.dll", R2Engine, (CModule module)) @@ -37,4 +39,6 @@ ON_DLL_LOAD("engine.dll", R2Engine, (CModule module)) g_pClientArray = module.Offset(0x12A53F90).As(); g_pServerState = module.Offset(0x12A53D48).As(); + + g_pGlobals = module.Offset(0x7C6F70).As(); } diff --git a/NorthstarDLL/engine/r2engine.h b/NorthstarDLL/engine/r2engine.h index bc242201..ff8876b8 100644 --- a/NorthstarDLL/engine/r2engine.h +++ b/NorthstarDLL/engine/r2engine.h @@ -201,4 +201,64 @@ namespace R2 extern server_state_t* g_pServerState; extern char* g_pModName; + + // clang-format off + OFFSET_STRUCT(CGlobalVars) + { + FIELD(0x0, + // Absolute time (per frame still - Use Plat_FloatTime() for a high precision real time + // perf clock, but not that it doesn't obey host_timescale/host_framerate) + double m_flRealTime); + + FIELDS(0x8, + // Absolute frame counter - continues to increase even if game is paused + int m_nFrameCount; + + // Non-paused frametime + float m_flAbsoluteFrameTime; + + // Current time + // + // On the client, this (along with tickcount) takes a different meaning based on what + // piece of code you're in: + // + // - While receiving network packets (like in PreDataUpdate/PostDataUpdate and proxies), + // this is set to the SERVER TICKCOUNT for that packet. There is no interval between + // the server ticks. + // [server_current_Tick * tick_interval] + // + // - While rendering, this is the exact client clock + // [client_current_tick * tick_interval + interpolation_amount] + // + // - During prediction, this is based on the client's current tick: + // [client_current_tick * tick_interval] + float m_flCurTime; + ) + + FIELDS(0x30, + // Time spent on last server or client frame (has nothing to do with think intervals) + float m_flFrameTime; + + // current maxplayers setting + int m_nMaxClients; + ) + + FIELDS(0x3C, + // Simulation ticks - does not increase when game is paused + uint32_t m_nTickCount; // this is weird and doesn't seem to increase once per frame? + + // Simulation tick interval + float m_flTickInterval; + ) + + FIELDS(0x60, + const char* m_pMapName; + int m_nMapVersion; + ) + + //FIELD(0x98, double m_flRealTime); // again? + }; + // clang-format on + + extern CGlobalVars* g_pGlobals; } // namespace R2 diff --git a/NorthstarDLL/engine/runframe.cpp b/NorthstarDLL/engine/runframe.cpp index d81356f2..3df93f54 100644 --- a/NorthstarDLL/engine/runframe.cpp +++ b/NorthstarDLL/engine/runframe.cpp @@ -5,6 +5,7 @@ #include "server/serverpresence.h" AUTOHOOK_INIT() + // clang-format off AUTOHOOK(CEngine__Frame, engine.dll + 0x1C8650, void, __fastcall, (R2::CEngine* self)) @@ -12,6 +13,7 @@ void, __fastcall, (R2::CEngine* self)) { CEngine__Frame(self); } + ON_DLL_LOAD("engine.dll", RunFrame, (CModule module)) { AUTOHOOK_DISPATCH() diff --git a/NorthstarDLL/server/auth/bansystem.cpp b/NorthstarDLL/server/auth/bansystem.cpp index 56719ed9..47df495d 100644 --- a/NorthstarDLL/server/auth/bansystem.cpp +++ b/NorthstarDLL/server/auth/bansystem.cpp @@ -2,7 +2,6 @@ #include "pch.h" #include "bansystem.h" #include "serverauthentication.h" -#include "shared/maxplayers.h" #include "core/convar/concommand.h" #include "server/r2server.h" #include "engine/r2engine.h" @@ -184,7 +183,7 @@ void ConCommand_ban(const CCommand& args) if (args.ArgC() < 2) return; - for (int i = 0; i < R2::GetMaxPlayers(); i++) + for (int i = 0; i < R2::g_pGlobals->m_nMaxClients; i++) { R2::CBaseClient* player = &R2::g_pClientArray[i]; diff --git a/NorthstarDLL/server/auth/serverauthentication.cpp b/NorthstarDLL/server/auth/serverauthentication.cpp index f8180469..2f06f60f 100644 --- a/NorthstarDLL/server/auth/serverauthentication.cpp +++ b/NorthstarDLL/server/auth/serverauthentication.cpp @@ -6,7 +6,6 @@ #include "masterserver/masterserver.h" #include "server/serverpresence.h" #include "engine/hoststate.h" -#include "shared/maxplayers.h" #include "bansystem.h" #include "core/convar/concommand.h" #include "dedicated/dedicated.h" @@ -154,7 +153,7 @@ bool ServerAuthenticationManager::IsDuplicateAccount(R2::CBaseClient* pPlayer, c return false; bool bHasUidPlayer = false; - for (int i = 0; i < R2::GetMaxPlayers(); i++) + for (int i = 0; i < R2::g_pGlobals->m_nMaxClients; i++) if (&R2::g_pClientArray[i] != pPlayer && !strcmp(pPlayerUid, R2::g_pClientArray[i].m_UID)) return true; diff --git a/NorthstarDLL/server/buildainfile.cpp b/NorthstarDLL/server/buildainfile.cpp index f6dc4717..d1150a6b 100644 --- a/NorthstarDLL/server/buildainfile.cpp +++ b/NorthstarDLL/server/buildainfile.cpp @@ -174,14 +174,12 @@ struct CAI_Network }; #pragma pack(pop) -char** pUnkServerMapversionGlobal; - ConVar* Cvar_ns_ai_dumpAINfileFromLoad; void DumpAINInfo(CAI_Network* aiNetwork) { fs::path writePath(fmt::format("{}/maps/graphs", R2::g_pModName)); - writePath /= R2::g_pHostState->m_levelName; + writePath /= R2::g_pGlobals->m_pMapName; writePath += ".ain"; // dump from memory @@ -196,9 +194,8 @@ void DumpAINInfo(CAI_Network* aiNetwork) spdlog::info("writing ainet version: {}", AINET_VERSION_NUMBER); writeStream.write((char*)&AINET_VERSION_NUMBER, sizeof(int)); - // could probably be cleaner but whatever - int mapVersion = *(int*)(*pUnkServerMapversionGlobal + 104); - spdlog::info("writing map version: {}", mapVersion); // temp + int mapVersion = R2::g_pGlobals->m_nMapVersion; + spdlog::info("writing map version: {}", mapVersion); writeStream.write((char*)&mapVersion, sizeof(int)); spdlog::info("writing placeholder crc: {}", PLACEHOLDER_CRC); writeStream.write((char*)&PLACEHOLDER_CRC, sizeof(int)); @@ -396,5 +393,4 @@ ON_DLL_LOAD("server.dll", BuildAINFile, (CModule module)) pppUnkNodeStruct0s = module.Offset(0x1063BE0).As(); pUnkLinkStruct1Count = module.Offset(0x1063AA8).As(); pppUnkStruct1s = module.Offset(0x1063A90).As(); - pUnkServerMapversionGlobal = module.Offset(0xBFBE08).As(); } diff --git a/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp b/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp index 49f80bab..135cfb83 100644 --- a/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp +++ b/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp @@ -4,7 +4,6 @@ #include "client/r2client.h" #include "engine/r2engine.h" #include "server/r2server.h" -#include "shared/maxplayers.h" #include "core/tier0.h" #include "core/math/vector.h" #include "server/auth/serverauthentication.h" @@ -13,22 +12,26 @@ AUTOHOOK_INIT() ServerLimitsManager* g_pServerLimits; +float (*CEngineServer__GetTimescale)(); + // todo: make this work on higher timescales, also possibly disable when sv_cheats is set void ServerLimitsManager::RunFrame(double flCurrentTime, float flFrameTime) { if (Cvar_sv_antispeedhack_enable->GetBool()) { // for each player, set their usercmd processing budget for the frame to the last frametime for the server - for (int i = 0; i < R2::GetMaxPlayers(); i++) + for (int i = 0; i < R2::g_pGlobals->m_nMaxClients; i++) { R2::CBaseClient* player = &R2::g_pClientArray[i]; if (m_PlayerLimitData.find(player) != m_PlayerLimitData.end()) { PlayerLimitData* pLimitData = &g_pServerLimits->m_PlayerLimitData[player]; - if (pLimitData->flFrameUserCmdBudget < 0.016666667 * Cvar_sv_antispeedhack_maxtickbudget->GetFloat()) - pLimitData->flFrameUserCmdBudget += - fmax(flFrameTime, 0.016666667) * g_pServerLimits->Cvar_sv_antispeedhack_budgetincreasemultiplier->GetFloat(); + if (pLimitData->flFrameUserCmdBudget < R2::g_pGlobals->m_flTickInterval * Cvar_sv_antispeedhack_maxtickbudget->GetFloat()) + { + pLimitData->flFrameUserCmdBudget += g_pServerLimits->Cvar_sv_antispeedhack_budgetincreasemultiplier->GetFloat() * + fmax(flFrameTime, R2::g_pGlobals->m_flFrameTime * CEngineServer__GetTimescale()); + } } } } @@ -37,7 +40,8 @@ void ServerLimitsManager::RunFrame(double flCurrentTime, float flFrameTime) void ServerLimitsManager::AddPlayer(R2::CBaseClient* player) { PlayerLimitData limitData; - limitData.flFrameUserCmdBudget = 0.016666667 * Cvar_sv_antispeedhack_maxtickbudget->GetFloat(); + limitData.flFrameUserCmdBudget = + R2::g_pGlobals->m_flTickInterval * CEngineServer__GetTimescale() * Cvar_sv_antispeedhack_maxtickbudget->GetFloat(); m_PlayerLimitData.insert(std::make_pair(player, limitData)); } @@ -53,10 +57,10 @@ bool ServerLimitsManager::CheckStringCommandLimits(R2::CBaseClient* player) if (CVar_sv_quota_stringcmdspersecond->GetInt() != -1) { // note: this isn't super perfect, legit clients can trigger it in lobby if they try, mostly good enough tho imo - if (Tier0::Plat_FloatTime() - m_PlayerLimitData[player].lastClientCommandQuotaStart >= 1.0) + if (R2::g_pGlobals->m_flCurTime - m_PlayerLimitData[player].lastClientCommandQuotaStart >= 1.0) { // reset quota - m_PlayerLimitData[player].lastClientCommandQuotaStart = Tier0::Plat_FloatTime(); + m_PlayerLimitData[player].lastClientCommandQuotaStart = R2::g_pGlobals->m_flCurTime; m_PlayerLimitData[player].numClientCommandsInQuota = 0; } @@ -73,9 +77,9 @@ bool ServerLimitsManager::CheckStringCommandLimits(R2::CBaseClient* player) bool ServerLimitsManager::CheckChatLimits(R2::CBaseClient* player) { - if (Tier0::Plat_FloatTime() - m_PlayerLimitData[player].lastSayTextLimitStart >= 1.0) + if (R2::g_pGlobals->m_flCurTime - m_PlayerLimitData[player].lastSayTextLimitStart >= 1.0) { - m_PlayerLimitData[player].lastSayTextLimitStart = Tier0::Plat_FloatTime(); + m_PlayerLimitData[player].lastSayTextLimitStart = R2::g_pGlobals->m_flCurTime; m_PlayerLimitData[player].sayTextLimitCount = 0; } @@ -97,7 +101,7 @@ char, __fastcall, (void* self, void* buf)) NETCHANLIMIT_KICK }; - double startTime = Tier0::Plat_FloatTime(); + double startTime = R2::g_pGlobals->m_flCurTime; char ret = CNetChan__ProcessMessages(self, buf); // check processing limits, unless we're in a level transition @@ -118,7 +122,7 @@ char, __fastcall, (void* self, void* buf)) g_pServerLimits->m_PlayerLimitData[sender].lastNetChanProcessingLimitStart = startTime; g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime = 0.0; } - g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime += (Tier0::Plat_FloatTime() * 1000) - (startTime * 1000); + g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime += (R2::g_pGlobals->m_flCurTime * 1000) - (startTime * 1000); if (g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime >= g_pServerLimits->Cvar_net_chan_limit_msec_per_sec->GetInt()) @@ -169,12 +173,12 @@ bool, , (void* a1, R2::netpacket_t* packet)) memcpy(sendData->ip, packet->adr.ip, 16); } - if (Tier0::Plat_FloatTime() < sendData->timeoutEnd) + if (R2::g_pGlobals->m_flCurTime < sendData->timeoutEnd) return false; - if (Tier0::Plat_FloatTime() - sendData->lastQuotaStart >= 1.0) + if (R2::g_pGlobals->m_flCurTime - sendData->lastQuotaStart >= 1.0) { - sendData->lastQuotaStart = Tier0::Plat_FloatTime(); + sendData->lastQuotaStart = R2::g_pGlobals->m_flCurTime; sendData->packetCount = 0; } @@ -188,7 +192,7 @@ bool, , (void* a1, R2::netpacket_t* packet)) packet->data[4]); // timeout for a minute - sendData->timeoutEnd = Tier0::Plat_FloatTime() + 60.0; + sendData->timeoutEnd = R2::g_pGlobals->m_flCurTime + 60.0; return false; } } @@ -250,8 +254,6 @@ void, __fastcall, (void* self, R2::CBasePlayer* player, SV_CUserCmd* pUserCmd, u spdlog::warn("player {} went over usercmd budget ({})", pClient->m_Name, pLimitData->flFrameUserCmdBudget); return; } - // else - // spdlog::info("{}: {}", pClient->m_Name, pLimitData->flFrameUserCmdBudget); } } @@ -284,12 +286,14 @@ ON_DLL_LOAD_RELIESON("engine.dll", ServerLimits, ConVar, (CModule module)) "sv_antispeedhack_maxtickbudget", "64", FCVAR_GAMEDLL, - "Maximum number of client-issued usercmd ticks that can be replayed in packet loss conditions, 0 to allow no restrictions"); + "Maximum number of client-issued usercmd ticks that can be replayed in packet loss conditions"); g_pServerLimits->Cvar_sv_antispeedhack_budgetincreasemultiplier = new ConVar( "sv_antispeedhack_budgetincreasemultiplier", - "1.2", + "1", FCVAR_GAMEDLL, "Increase usercmd processing budget by tickinterval * value per tick"); + + CEngineServer__GetTimescale = module.Offset(0x240840).As(); } ON_DLL_LOAD("server.dll", ServerLimitsServer, (CModule module)) diff --git a/NorthstarDLL/shared/keyvalues.cpp b/NorthstarDLL/shared/keyvalues.cpp index fe7d6299..25155dde 100644 --- a/NorthstarDLL/shared/keyvalues.cpp +++ b/NorthstarDLL/shared/keyvalues.cpp @@ -211,8 +211,15 @@ KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate) return this; const char* pSubStr = strchr(pszKeyName, '/'); + const char* pSearchStr = pszKeyName; + if (pSubStr && !*(pSubStr + 1)) + { + // if key name is just '/', then use it as a key directly + pSearchStr = pSubStr; + pSubStr = nullptr; + } - HKeySymbol iSearchStr = KeyValuesSystem()->m_pVtable->GetSymbolForString(KeyValuesSystem(), pszKeyName, bCreate); + HKeySymbol iSearchStr = KeyValuesSystem()->m_pVtable->GetSymbolForString(KeyValuesSystem(), pSearchStr, bCreate); if (iSearchStr == INVALID_KEY_SYMBOL) { // not found, couldn't possibly be in key value list @@ -222,7 +229,7 @@ KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate) KeyValues* pLastKVs = nullptr; KeyValues* pCurrentKVs; // find the searchStr in the current peer list - for (pCurrentKVs = m_pSub; pCurrentKVs != NULL; pCurrentKVs = pCurrentKVs->m_pPeer) + for (pCurrentKVs = m_pSub; pCurrentKVs != nullptr; pCurrentKVs = pCurrentKVs->m_pPeer) { pLastKVs = pCurrentKVs; // record the last item looked at (for if we need to append to the end of the list) @@ -232,7 +239,7 @@ KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate) } if (!pCurrentKVs && m_pChain) - pCurrentKVs = m_pChain->FindKey(pszKeyName, false); + pCurrentKVs = m_pChain->FindKey(pSearchStr, false); // make sure a key was found if (!pCurrentKVs) @@ -240,7 +247,7 @@ KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate) if (bCreate) { // we need to create a new key - pCurrentKVs = new KeyValues(pszKeyName); + pCurrentKVs = new KeyValues(pSearchStr); // Assert(dat != NULL); // insert new key at end of list @@ -249,7 +256,7 @@ KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate) else m_pSub = pCurrentKVs; - pCurrentKVs->m_pPeer = NULL; + pCurrentKVs->m_pPeer = nullptr; // a key graduates to be a submsg as soon as it's m_pSub is set // this should be the only place m_pSub is set @@ -257,7 +264,7 @@ KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate) } else { - return NULL; + return nullptr; } } diff --git a/NorthstarDLL/shared/playlist.cpp b/NorthstarDLL/shared/playlist.cpp index 2fb856b3..7c8f7312 100644 --- a/NorthstarDLL/shared/playlist.cpp +++ b/NorthstarDLL/shared/playlist.cpp @@ -4,6 +4,7 @@ #include "core/convar/convar.h" #include "squirrel/squirrel.h" #include "engine/hoststate.h" +#include "engine/r2engine.h" #include "server/serverpresence.h" AUTOHOOK_INIT() @@ -26,7 +27,7 @@ char, __fastcall, (void* a1, void* a2)) { // the private_match playlist on mp_lobby is the only situation where there should be any legitimate sending of this netmessage if (!Cvar_ns_use_clc_SetPlaylistVarOverride->GetBool() || strcmp(R2::GetCurrentPlaylistName(), "private_match") || - strcmp(R2::g_pHostState->m_levelName, "mp_lobby")) + strcmp(R2::g_pGlobals->m_pMapName, "mp_lobby")) return 1; return clc_SetPlaylistVarOverride__Process(a1, a2); diff --git a/NorthstarDLL/util/printmaps.cpp b/NorthstarDLL/util/printmaps.cpp index e0192d69..0a5f73f2 100644 --- a/NorthstarDLL/util/printmaps.cpp +++ b/NorthstarDLL/util/printmaps.cpp @@ -115,10 +115,10 @@ int, __fastcall, (const char const* cmdname, const char const* partial, char com // don't update our map list often from this func, only refresh every 10 seconds so we avoid constantly reading fs static double flLastAutocompleteRefresh = -999; - if (flLastAutocompleteRefresh + 10.0 < Tier0::Plat_FloatTime()) + if (flLastAutocompleteRefresh + 10.0 < R2::g_pGlobals->m_flRealTime) { RefreshMapList(); - flLastAutocompleteRefresh = Tier0::Plat_FloatTime(); + flLastAutocompleteRefresh = R2::g_pGlobals->m_flRealTime; } // use a custom autocomplete func for all map loading commands -- cgit v1.2.3