NorthstarLauncher/NorthstarDLL/engine/hoststate.cpp

192 lines
6.2 KiB
C++

#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*>();
}