aboutsummaryrefslogtreecommitdiff
path: root/primedev/engine/hoststate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'primedev/engine/hoststate.cpp')
-rw-r--r--primedev/engine/hoststate.cpp191
1 files changed, 191 insertions, 0 deletions
diff --git a/primedev/engine/hoststate.cpp b/primedev/engine/hoststate.cpp
new file mode 100644
index 00000000..ec728afb
--- /dev/null
+++ b/primedev/engine/hoststate.cpp
@@ -0,0 +1,191 @@
+#include "engine/hoststate.h"
+#include "masterserver/masterserver.h"
+#include "server/auth/serverauthentication.h"
+#include "server/serverpresence.h"
+#include "shared/playlist.h"
+#include "core/tier0.h"
+#include "engine/r2engine.h"
+#include "shared/exploit_fixes/ns_limits.h"
+#include "squirrel/squirrel.h"
+#include "plugins/plugins.h"
+#include "plugins/pluginbackend.h"
+
+AUTOHOOK_INIT()
+
+CHostState* g_pHostState;
+
+std::string sLastMode;
+
+VAR_AT(engine.dll + 0x13FA6070, ConVar*, Cvar_hostport);
+FUNCTION_AT(engine.dll + 0x1232C0, void, __fastcall, _Cmd_Exec_f, (const CCommand& arg, bool bOnlyIfExists, bool bUseWhitelists));
+
+void ServerStartingOrChangingMap()
+{
+ ConVar* Cvar_mp_gamemode = g_pCVar->FindVar("mp_gamemode");
+
+ // directly call _Cmd_Exec_f to avoid weirdness with ; being in mp_gamemode potentially
+ // if we ran exec {mp_gamemode} and mp_gamemode contained semicolons, this could be used to execute more commands
+ char* commandBuf[1040]; // assumedly this is the size of CCommand since we don't have an actual constructor
+ memset(commandBuf, 0, sizeof(commandBuf));
+ CCommand tempCommand = *(CCommand*)&commandBuf;
+ if (sLastMode.length() &&
+ CCommand__Tokenize(tempCommand, fmt::format("exec server/cleanup_gamemode_{}", sLastMode).c_str(), cmd_source_t::kCommandSrcCode))
+ _Cmd_Exec_f(tempCommand, false, false);
+
+ memset(commandBuf, 0, sizeof(commandBuf));
+ if (CCommand__Tokenize(
+ tempCommand,
+ fmt::format("exec server/setup_gamemode_{}", sLastMode = Cvar_mp_gamemode->GetString()).c_str(),
+ cmd_source_t::kCommandSrcCode))
+ {
+ _Cmd_Exec_f(tempCommand, false, false);
+ }
+
+ Cbuf_Execute(); // exec everything right now
+
+ // net_data_block_enabled is required for sp, force it if we're on an sp map
+ // sucks for security but just how it be
+ if (!strncmp(g_pHostState->m_levelName, "sp_", 3))
+ {
+ g_pCVar->FindVar("net_data_block_enabled")->SetValue(true);
+ g_pServerAuthentication->m_bStartingLocalSPGame = true;
+ }
+ else
+ g_pServerAuthentication->m_bStartingLocalSPGame = false;
+}
+
+// clang-format off
+AUTOHOOK(CHostState__State_NewGame, engine.dll + 0x16E7D0,
+void, __fastcall, (CHostState* self))
+// clang-format on
+{
+ spdlog::info("HostState: NewGame");
+
+ Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", cmd_source_t::kCommandSrcCode);
+ Cbuf_Execute();
+
+ // need to do this to ensure we don't go to private match
+ if (g_pServerAuthentication->m_bNeedLocalAuthForNewgame)
+ R2::SetCurrentPlaylist("tdm");
+
+ ServerStartingOrChangingMap();
+
+ double dStartTime = Plat_FloatTime();
+ CHostState__State_NewGame(self);
+ spdlog::info("loading took {}s", Plat_FloatTime() - dStartTime);
+
+ // setup server presence
+ g_pServerPresence->CreatePresence();
+ g_pServerPresence->SetMap(g_pHostState->m_levelName, true);
+ g_pServerPresence->SetPlaylist(R2::GetCurrentPlaylistName());
+ g_pServerPresence->SetPort(Cvar_hostport->GetInt());
+
+ g_pServerAuthentication->m_bNeedLocalAuthForNewgame = false;
+}
+
+// clang-format off
+AUTOHOOK(CHostState__State_LoadGame, engine.dll + 0x16E730,
+void, __fastcall, (CHostState* self))
+// clang-format on
+{
+ // singleplayer server starting
+ // useless in 99% of cases but without it things could potentially break very much
+
+ spdlog::info("HostState: LoadGame");
+
+ Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", cmd_source_t::kCommandSrcCode);
+ Cbuf_Execute();
+
+ // this is normally done in ServerStartingOrChangingMap(), but seemingly the map name isn't set at this point
+ g_pCVar->FindVar("net_data_block_enabled")->SetValue(true);
+ g_pServerAuthentication->m_bStartingLocalSPGame = true;
+
+ double dStartTime = Plat_FloatTime();
+ CHostState__State_LoadGame(self);
+ spdlog::info("loading took {}s", Plat_FloatTime() - dStartTime);
+
+ // no server presence, can't do it because no map name in hoststate
+ // and also not super important for sp saves really
+
+ g_pServerAuthentication->m_bNeedLocalAuthForNewgame = false;
+}
+
+// clang-format off
+AUTOHOOK(CHostState__State_ChangeLevelMP, engine.dll + 0x16E520,
+void, __fastcall, (CHostState* self))
+// clang-format on
+{
+ spdlog::info("HostState: ChangeLevelMP");
+
+ ServerStartingOrChangingMap();
+
+ double dStartTime = Plat_FloatTime();
+ CHostState__State_ChangeLevelMP(self);
+ spdlog::info("loading took {}s", Plat_FloatTime() - dStartTime);
+
+ g_pServerPresence->SetMap(g_pHostState->m_levelName);
+}
+
+// clang-format off
+AUTOHOOK(CHostState__State_GameShutdown, engine.dll + 0x16E640,
+void, __fastcall, (CHostState* self))
+// clang-format on
+{
+ spdlog::info("HostState: GameShutdown");
+
+ g_pServerPresence->DestroyPresence();
+
+ CHostState__State_GameShutdown(self);
+
+ // run gamemode cleanup cfg now instead of when we start next map
+ if (sLastMode.length())
+ {
+ char* commandBuf[1040]; // assumedly this is the size of CCommand since we don't have an actual constructor
+ memset(commandBuf, 0, sizeof(commandBuf));
+ CCommand tempCommand = *(CCommand*)&commandBuf;
+ if (CCommand__Tokenize(
+ tempCommand, fmt::format("exec server/cleanup_gamemode_{}", sLastMode).c_str(), cmd_source_t::kCommandSrcCode))
+ {
+ _Cmd_Exec_f(tempCommand, false, false);
+ Cbuf_Execute();
+ }
+
+ sLastMode.clear();
+ }
+}
+
+// clang-format off
+AUTOHOOK(CHostState__FrameUpdate, engine.dll + 0x16DB00,
+void, __fastcall, (CHostState* self, double flCurrentTime, float flFrameTime))
+// clang-format on
+{
+ CHostState__FrameUpdate(self, flCurrentTime, flFrameTime);
+
+ if (*g_pServerState == server_state_t::ss_active)
+ {
+ // update server presence
+ g_pServerPresence->RunFrame(flCurrentTime);
+
+ // update limits for frame
+ g_pServerLimits->RunFrame(flCurrentTime, flFrameTime);
+ }
+
+ // Run Squirrel message buffer
+ if (g_pSquirrel<ScriptContext::UI>->m_pSQVM != nullptr && g_pSquirrel<ScriptContext::UI>->m_pSQVM->sqvm != nullptr)
+ g_pSquirrel<ScriptContext::UI>->ProcessMessageBuffer();
+
+ if (g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM != nullptr && g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm != nullptr)
+ g_pSquirrel<ScriptContext::CLIENT>->ProcessMessageBuffer();
+
+ if (g_pSquirrel<ScriptContext::SERVER>->m_pSQVM != nullptr && g_pSquirrel<ScriptContext::SERVER>->m_pSQVM->sqvm != nullptr)
+ g_pSquirrel<ScriptContext::SERVER>->ProcessMessageBuffer();
+
+ g_pPluginManager->RunFrame();
+}
+
+ON_DLL_LOAD_RELIESON("engine.dll", HostState, ConVar, (CModule module))
+{
+ AUTOHOOK_DISPATCH()
+
+ g_pHostState = module.Offset(0x7CF180).RCast<CHostState*>();
+}