diff options
-rw-r--r-- | NorthstarDedicatedTest/ExploitFixes.cpp | 2 | ||||
-rw-r--r-- | NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj | 4 | ||||
-rw-r--r-- | NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters | 90 | ||||
-rw-r--r-- | NorthstarDedicatedTest/clientchathooks.h | 1 | ||||
-rw-r--r-- | NorthstarDedicatedTest/convar.cpp | 16 | ||||
-rw-r--r-- | NorthstarDedicatedTest/convar.h | 2 | ||||
-rw-r--r-- | NorthstarDedicatedTest/dedicated.cpp | 15 | ||||
-rw-r--r-- | NorthstarDedicatedTest/gameutils.cpp | 6 | ||||
-rw-r--r-- | NorthstarDedicatedTest/gameutils.h | 41 | ||||
-rw-r--r-- | NorthstarDedicatedTest/host.cpp | 55 | ||||
-rw-r--r-- | NorthstarDedicatedTest/host.h | 1 | ||||
-rw-r--r-- | NorthstarDedicatedTest/hoststate.cpp | 107 | ||||
-rw-r--r-- | NorthstarDedicatedTest/hoststate.h | 45 | ||||
-rw-r--r-- | NorthstarDedicatedTest/masterserver.cpp | 144 | ||||
-rw-r--r-- | NorthstarDedicatedTest/masterserver.h | 35 | ||||
-rw-r--r-- | NorthstarDedicatedTest/misccommands.cpp | 9 | ||||
-rw-r--r-- | NorthstarDedicatedTest/playlist.h | 2 | ||||
-rw-r--r-- | NorthstarDedicatedTest/serverauthentication.cpp | 3 |
18 files changed, 332 insertions, 246 deletions
diff --git a/NorthstarDedicatedTest/ExploitFixes.cpp b/NorthstarDedicatedTest/ExploitFixes.cpp index 3850b5a7..3250f3b8 100644 --- a/NorthstarDedicatedTest/ExploitFixes.cpp +++ b/NorthstarDedicatedTest/ExploitFixes.cpp @@ -153,7 +153,7 @@ KHOOK(CClient_ProcessSetConVar, ("engine.dll", "48 8B D1 48 8B 49 18 48 8B 01 48 if (areWeServer) { if (realVar) - isValidFlags = ConVar::IsFlagSet(realVar, FCVAR_USERINFO); // ConVar MUST be userinfo var + isValidFlags = realVar->IsFlagSet(FCVAR_USERINFO); // ConVar MUST be userinfo var } else { diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index c523534a..a12a10f5 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -123,6 +123,8 @@ <ClInclude Include="debugoverlay.h" /> <ClInclude Include="clientruihooks.h" /> <ClInclude Include="clientvideooverrides.h" /> + <ClInclude Include="host.h" /> + <ClInclude Include="hoststate.h" /> <ClInclude Include="localchatwriter.h" /> <ClInclude Include="ns_version.h" /> <ClInclude Include="plugins.h" /> @@ -595,6 +597,8 @@ <ClCompile Include="gameutils.cpp" /> <ClCompile Include="hooks.cpp" /> <ClCompile Include="hookutils.cpp" /> + <ClCompile Include="host.cpp" /> + <ClCompile Include="hoststate.cpp" /> <ClCompile Include="keyvalues.cpp" /> <ClCompile Include="latencyflex.cpp" /> <ClCompile Include="localchatwriter.cpp" /> diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 1cb6cadd..cfd9c5ef 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -133,6 +133,12 @@ <Filter Include="Source Files\Shared\Mods\Compiled Assets"> <UniqueIdentifier>{14fc0931-acad-46ec-a55e-94f4469d4235}</UniqueIdentifier> </Filter> + <Filter Include="Header Files\Client\Scripted"> + <UniqueIdentifier>{9ce4bfce-f214-4bc1-9dc7-f3219900718a}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Client\Scripted"> + <UniqueIdentifier>{51910ba0-2ff8-461d-9f67-8d7907b57d22}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClInclude Include="pch.h"> @@ -561,12 +567,6 @@ <ClInclude Include="serverauthentication.h"> <Filter>Header Files\Server\Authentication</Filter> </ClInclude> - <ClInclude Include="scriptmodmenu.h"> - <Filter>Header Files\Client</Filter> - </ClInclude> - <ClInclude Include="scriptserverbrowser.h"> - <Filter>Header Files\Client</Filter> - </ClInclude> <ClInclude Include="keyvalues.h"> <Filter>Header Files\Shared\Mods\Compiled</Filter> </ClInclude> @@ -597,18 +597,12 @@ <ClInclude Include="clientauthhooks.h"> <Filter>Header Files\Client</Filter> </ClInclude> - <ClInclude Include="scriptbrowserhooks.h"> - <Filter>Header Files\Client</Filter> - </ClInclude> <ClInclude Include="gameutils.h"> <Filter>Header Files\Shared\Game Functions</Filter> </ClInclude> <ClInclude Include="memalloc.h"> <Filter>Header Files\Shared</Filter> </ClInclude> - <ClInclude Include="scriptmainmenupromos.h"> - <Filter>Header Files\Client</Filter> - </ClInclude> <ClInclude Include="miscclientfixes.h"> <Filter>Header Files\Client</Filter> </ClInclude> @@ -1464,15 +1458,9 @@ <ClInclude Include="serverchathooks.h"> <Filter>Header Files\Server</Filter> </ClInclude> - <ClInclude Include="clientchathooks.h"> - <Filter>Header Files\Client</Filter> - </ClInclude> <ClInclude Include="localchatwriter.h"> <Filter>Header Files\Client</Filter> </ClInclude> - <ClInclude Include="scriptservertoclientstringcommand.h"> - <Filter>Header Files\Client</Filter> - </ClInclude> <ClInclude Include="plugins.h"> <Filter>Header Files</Filter> </ClInclude> @@ -1512,6 +1500,30 @@ <ClInclude Include="tier0.h"> <Filter>Header Files\Shared\Game Functions</Filter> </ClInclude> + <ClInclude Include="clientchathooks.h"> + <Filter>Header Files\Client\Scripted</Filter> + </ClInclude> + <ClInclude Include="scriptbrowserhooks.h"> + <Filter>Header Files\Client\Scripted</Filter> + </ClInclude> + <ClInclude Include="scriptmainmenupromos.h"> + <Filter>Header Files\Client\Scripted</Filter> + </ClInclude> + <ClInclude Include="scriptmodmenu.h"> + <Filter>Header Files\Client\Scripted</Filter> + </ClInclude> + <ClInclude Include="scriptserverbrowser.h"> + <Filter>Header Files\Client\Scripted</Filter> + </ClInclude> + <ClInclude Include="scriptservertoclientstringcommand.h"> + <Filter>Header Files\Client\Scripted</Filter> + </ClInclude> + <ClInclude Include="host.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> + <ClInclude Include="hoststate.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="dllmain.cpp"> @@ -1562,12 +1574,6 @@ <ClCompile Include="serverauthentication.cpp"> <Filter>Source Files\Server\Authentication</Filter> </ClCompile> - <ClCompile Include="scriptmodmenu.cpp"> - <Filter>Source Files\Client</Filter> - </ClCompile> - <ClCompile Include="scriptserverbrowser.cpp"> - <Filter>Source Files\Client</Filter> - </ClCompile> <ClCompile Include="keyvalues.cpp"> <Filter>Source Files\Shared\Mods\Compiled Assets</Filter> </ClCompile> @@ -1598,15 +1604,9 @@ <ClCompile Include="clientauthhooks.cpp"> <Filter>Source Files\Client</Filter> </ClCompile> - <ClCompile Include="scriptbrowserhooks.cpp"> - <Filter>Source Files\Client</Filter> - </ClCompile> <ClCompile Include="memalloc.cpp"> <Filter>Source Files\Shared</Filter> </ClCompile> - <ClCompile Include="scriptmainmenupromos.cpp"> - <Filter>Source Files\Client</Filter> - </ClCompile> <ClCompile Include="miscclientfixes.cpp"> <Filter>Source Files\Client</Filter> </ClCompile> @@ -1646,15 +1646,9 @@ <ClCompile Include="serverchathooks.cpp"> <Filter>Source Files\Server</Filter> </ClCompile> - <ClCompile Include="clientchathooks.cpp"> - <Filter>Source Files\Client</Filter> - </ClCompile> <ClCompile Include="localchatwriter.cpp"> <Filter>Source Files\Client</Filter> </ClCompile> - <ClCompile Include="scriptservertoclientstringcommand.cpp"> - <Filter>Source Files\Client</Filter> - </ClCompile> <ClCompile Include="plugins.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -1679,6 +1673,30 @@ <ClCompile Include="tier0.cpp"> <Filter>Source Files\Shared\Game Functions</Filter> </ClCompile> + <ClCompile Include="hoststate.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + <ClCompile Include="host.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> + <ClCompile Include="scriptmainmenupromos.cpp"> + <Filter>Source Files\Client\Scripted</Filter> + </ClCompile> + <ClCompile Include="clientchathooks.cpp"> + <Filter>Source Files\Client\Scripted</Filter> + </ClCompile> + <ClCompile Include="scriptmodmenu.cpp"> + <Filter>Source Files\Client\Scripted</Filter> + </ClCompile> + <ClCompile Include="scriptservertoclientstringcommand.cpp"> + <Filter>Source Files\Client\Scripted</Filter> + </ClCompile> + <ClCompile Include="scriptserverbrowser.cpp"> + <Filter>Source Files\Client\Scripted</Filter> + </ClCompile> + <ClCompile Include="scriptbrowserhooks.cpp"> + <Filter>Source Files\Client\Scripted</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <MASM Include="audio_asm.asm"> diff --git a/NorthstarDedicatedTest/clientchathooks.h b/NorthstarDedicatedTest/clientchathooks.h index d8f831c2..6f70f09b 100644 --- a/NorthstarDedicatedTest/clientchathooks.h +++ b/NorthstarDedicatedTest/clientchathooks.h @@ -1,2 +1 @@ #pragma once -#include "pch.h"
\ No newline at end of file diff --git a/NorthstarDedicatedTest/convar.cpp b/NorthstarDedicatedTest/convar.cpp index c8e76e47..3ae02463 100644 --- a/NorthstarDedicatedTest/convar.cpp +++ b/NorthstarDedicatedTest/convar.cpp @@ -26,9 +26,6 @@ ConVarMallocType conVarMalloc; void* g_pConVar_Vtable = nullptr; void* g_pIConVar_Vtable = nullptr; -typedef bool (*CvarIsFlagSetType)(ConVar* self, int flags); -CvarIsFlagSetType CvarIsFlagSet; - //----------------------------------------------------------------------------- // Purpose: ConVar interface initialization //----------------------------------------------------------------------------- @@ -42,9 +39,6 @@ ON_DLL_LOAD("engine.dll", ConVar, [](HMODULE baseAddress) g_pCVarInterface = new SourceInterface<CCvar>("vstdlib.dll", "VEngineCvar007"); g_pCVar = *g_pCVarInterface; - - HookEnabler hook; - ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x417FA0, &ConVar::IsFlagSet, reinterpret_cast<LPVOID*>(&CvarIsFlagSet)); }) //----------------------------------------------------------------------------- @@ -475,16 +469,12 @@ bool ConVar::IsCommand(void) const //----------------------------------------------------------------------------- // Purpose: Test each ConVar query before setting the value. -// Input : *pConVar - nFlags +// Input : nFlags // Output : False if change is permitted, true if not. //----------------------------------------------------------------------------- -bool ConVar::IsFlagSet(ConVar* pConVar, int nFlags) +bool ConVar::IsFlagSet(int nFlags) const { - // unrestrict FCVAR_DEVELOPMENTONLY and FCVAR_HIDDEN - if (pConVar && (nFlags == FCVAR_DEVELOPMENTONLY || nFlags == FCVAR_HIDDEN)) - return false; - - return CvarIsFlagSet(pConVar, nFlags); + return m_ConCommandBase.IsFlagSet(nFlags); } //----------------------------------------------------------------------------- diff --git a/NorthstarDedicatedTest/convar.h b/NorthstarDedicatedTest/convar.h index 8dbbd07d..d766933d 100644 --- a/NorthstarDedicatedTest/convar.h +++ b/NorthstarDedicatedTest/convar.h @@ -161,7 +161,7 @@ class ConVar bool IsRegistered(void) const; bool IsCommand(void) const; - static bool IsFlagSet(ConVar* pConVar, int nFlags); + bool IsFlagSet(int nFlags) const; struct CVValue_t { diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 41de0594..646439ab 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -5,10 +5,12 @@ #include "gameutils.h" #include "tier0.h" #include "playlist.h" +#include "hoststate.h" #include "serverauthentication.h" #include "masterserver.h" using namespace Tier0; +using namespace R2; bool IsDedicated() { @@ -53,17 +55,14 @@ void RunServer(CDedicatedExports* dedicated) if (!CommandLine()->CheckParm("+map")) CommandLine()->AppendParm("+map", g_pCVar->FindVar("match_defaultMap")->GetString()); + // ensure playlist initialises right, if we've not explicitly called setplaylist + SetCurrentPlaylist(GetCurrentPlaylistName()); + // run server autoexec and re-run commandline Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", cmd_source_t::kCommandSrcCode); Cbuf_AddText(Cbuf_GetCurrentPlayer(), "stuffcmds", cmd_source_t::kCommandSrcCode); Cbuf_Execute(); - // ensure playlist initialises right, if we've not explicitly called setplaylist - R2::SetCurrentPlaylist(R2::GetCurrentPlaylistName()); - - // note: we no longer manually set map and hoststate to start server in g_pHostState, we just use +map which seems to initialise stuff - // better - // get tickinterval ConVar* Cvar_base_tickinterval_mp = g_pCVar->FindVar("base_tickinterval_mp"); @@ -80,7 +79,7 @@ void RunServer(CDedicatedExports* dedicated) frameTitle = frameStart; // this way of getting playercount/maxplayers honestly really sucks, but not got any other methods of doing it rn - const char* maxPlayers = R2::GetCurrentPlaylistVar("max_players", false); + const char* maxPlayers = GetCurrentPlaylistVar("max_players", false); if (!maxPlayers) maxPlayers = "6"; @@ -90,7 +89,7 @@ void RunServer(CDedicatedExports* dedicated) g_pHostState->m_levelName, g_ServerAuthenticationManager->m_additionalPlayerData.size(), maxPlayers, - R2::GetCurrentPlaylistName()) + GetCurrentPlaylistName()) .c_str()); } diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp index d6e5840a..ce96a5e5 100644 --- a/NorthstarDedicatedTest/gameutils.cpp +++ b/NorthstarDedicatedTest/gameutils.cpp @@ -1,15 +1,13 @@ #include "pch.h" #include "convar.h" #include "gameutils.h" +#include "hoststate.h" // cmd.h Cbuf_GetCurrentPlayerType Cbuf_GetCurrentPlayer; Cbuf_AddTextType Cbuf_AddText; Cbuf_ExecuteType Cbuf_Execute; -// hoststate stuff -CHostState* g_pHostState; - // cengine stuff CEngine* g_pEngine; server_state_t* sv_m_State; @@ -30,7 +28,7 @@ void InitialiseEngineGameUtilFunctions(HMODULE baseAddress) Cbuf_AddText = (Cbuf_AddTextType)((char*)baseAddress + 0x1203B0); Cbuf_Execute = (Cbuf_ExecuteType)((char*)baseAddress + 0x1204B0); - g_pHostState = (CHostState*)((char*)baseAddress + 0x7CF180); + R2::g_pHostState = (R2::CHostState*)((char*)baseAddress + 0x7CF180); g_pEngine = *(CEngine**)((char*)baseAddress + 0x7D70C8); sv_m_State = (server_state_t*)((char*)baseAddress + 0x12A53D48); diff --git a/NorthstarDedicatedTest/gameutils.h b/NorthstarDedicatedTest/gameutils.h index 4d1b8fb7..d53c7abe 100644 --- a/NorthstarDedicatedTest/gameutils.h +++ b/NorthstarDedicatedTest/gameutils.h @@ -57,47 +57,6 @@ extern Cbuf_AddTextType Cbuf_AddText; typedef void (*Cbuf_ExecuteType)(); extern Cbuf_ExecuteType Cbuf_Execute; -// hoststate stuff -enum HostState_t -{ - HS_NEW_GAME = 0, - HS_LOAD_GAME, - HS_CHANGE_LEVEL_SP, - HS_CHANGE_LEVEL_MP, - HS_RUN, - HS_GAME_SHUTDOWN, - HS_SHUTDOWN, - HS_RESTART, -}; - -struct CHostState -{ - public: - HostState_t m_iCurrentState; - HostState_t m_iNextState; - - float m_vecLocation[3]; - float m_angLocation[3]; - - char m_levelName[32]; - char m_mapGroupName[32]; - char m_landmarkName[32]; - char m_saveName[32]; - float m_flShortFrameTime; // run a few one-tick frames to avoid large timesteps while loading assets - - bool m_activeGame; - bool m_bRememberLocation; - bool m_bBackgroundLevel; - bool m_bWaitingForConnection; - bool m_bLetToolsOverrideLoadGameEnts; // During a load game, this tells Foundry to override ents that are selected in Hammer. - bool m_bSplitScreenConnect; - bool m_bGameHasShutDownAndFlushedMemory; // This is false once we load a map into memory, and set to true once the map is unloaded and - // all memory flushed - bool m_bWorkshopMapDownloadPending; -}; - -extern CHostState* g_pHostState; - // cengine stuff enum EngineQuitState { diff --git a/NorthstarDedicatedTest/host.cpp b/NorthstarDedicatedTest/host.cpp new file mode 100644 index 00000000..9217c128 --- /dev/null +++ b/NorthstarDedicatedTest/host.cpp @@ -0,0 +1,55 @@ +#include "pch.h" +#include "host.h" +#include "convar.h" +#include "modmanager.h" +#include "gameutils.h" + +typedef void (*Host_InitType)(bool bDedicated); +Host_InitType Host_Init; +void Host_InitHook(bool bDedicated) +{ + Host_Init(bDedicated); + + // get all mod convars + std::vector<std::string> vModConvarNames; + for (auto& mod : g_ModManager->m_loadedMods) + for (auto& cvar : mod.ConVars) + vModConvarNames.push_back(cvar->Name); + + // strip hidden and devonly cvar flags + int iCvarsAltered = 0; + for (auto& pair : g_pCVar->DumpToMap()) + { + // don't remove from mod cvars + if (std::find(vModConvarNames.begin(), vModConvarNames.end(), pair.second->m_pszName) != vModConvarNames.end()) + continue; + + // strip flags + int flags = pair.second->GetFlags(); + if (flags & FCVAR_DEVELOPMENTONLY) + { + flags &= ~FCVAR_DEVELOPMENTONLY; + iCvarsAltered++; + } + + if (flags & FCVAR_HIDDEN) + { + flags &= ~FCVAR_HIDDEN; + iCvarsAltered++; + } + + pair.second->m_nFlags = flags; + } + + spdlog::info("Removed {} hidden/devonly cvar flags", iCvarsAltered); + + // run client autoexec if on client + if (!bDedicated) + Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_client", cmd_source_t::kCommandSrcCode); +} + +ON_DLL_LOAD("engine.dll", Host_Init, [](HMODULE baseAddress) +{ + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x155EA0, &Host_InitHook, reinterpret_cast<LPVOID*>(&Host_Init)); +})
\ No newline at end of file diff --git a/NorthstarDedicatedTest/host.h b/NorthstarDedicatedTest/host.h new file mode 100644 index 00000000..6f70f09b --- /dev/null +++ b/NorthstarDedicatedTest/host.h @@ -0,0 +1 @@ +#pragma once diff --git a/NorthstarDedicatedTest/hoststate.cpp b/NorthstarDedicatedTest/hoststate.cpp new file mode 100644 index 00000000..4782b559 --- /dev/null +++ b/NorthstarDedicatedTest/hoststate.cpp @@ -0,0 +1,107 @@ +#include "pch.h" +#include "hoststate.h" +#include "masterserver.h" +#include "serverauthentication.h" +#include "playlist.h" +#include "gameutils.h" +#include "tier0.h" + +using namespace R2; + +// use the R2 namespace for game funcs +namespace R2 +{ + CHostState* g_pHostState; +} // namespace R2 + +typedef void (*CHostState__State_NewGameType)(CHostState* hostState); +CHostState__State_NewGameType CHostState__State_NewGame; +void CHostState__State_NewGameHook(CHostState* hostState) +{ + 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_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame) + SetCurrentPlaylist("tdm"); + + // 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); + + double dStartTime = Tier0::Plat_FloatTime(); + CHostState__State_NewGame(hostState); + spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); + + int maxPlayers = 6; + const char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); + if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this + maxPlayers = std::stoi(maxPlayersVar); + + // Copy new server name cvar to source + Cvar_hostname->SetValue(Cvar_ns_server_name->GetString()); + + g_MasterServerManager->AddSelfToServerList( + Cvar_hostport->GetInt(), + Cvar_ns_player_auth_port->GetInt(), + Cvar_ns_server_name->GetString(), + Cvar_ns_server_desc->GetString(), + hostState->m_levelName, + GetCurrentPlaylistName(), + maxPlayers, + Cvar_ns_server_password->GetString()); + g_ServerAuthenticationManager->StartPlayerAuthServer(); + g_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame = false; +} + +typedef void (*CHostState__State_ChangeLevelMPType)(CHostState* hostState); +CHostState__State_ChangeLevelMPType CHostState__State_ChangeLevelMP; +void CHostState__State_ChangeLevelMPHook(CHostState* hostState) +{ + spdlog::info("HostState: ChangeLevelMP"); + + int maxPlayers = 6; + const char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); + if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this + maxPlayers = std::stoi(maxPlayersVar); + + // 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_MasterServerManager->UpdateServerMapAndPlaylist(hostState->m_levelName, GetCurrentPlaylistName(), maxPlayers); + + double dStartTime = Tier0::Plat_FloatTime(); + CHostState__State_ChangeLevelMP(hostState); + spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); +} + +typedef void (*CHostState__State_GameShutdownType)(CHostState* hostState); +CHostState__State_GameShutdownType CHostState__State_GameShutdown; +void CHostState__State_GameShutdownHook(CHostState* hostState) +{ + spdlog::info("HostState: GameShutdown"); + + g_MasterServerManager->RemoveSelfFromServerList(); + g_ServerAuthenticationManager->StopPlayerAuthServer(); + + CHostState__State_GameShutdown(hostState); +} + +ON_DLL_LOAD_RELIESON("engine.dll", HostState, ConVar, [](HMODULE baseAddress) +{ + Cvar_hostname = *(ConVar**)((char*)baseAddress + 0x1315bae8); + Cvar_hostport = (ConVar*)((char*)baseAddress + 0x13FA6070); + + HookEnabler hook; + ENABLER_CREATEHOOK( + hook, (char*)baseAddress + 0x16E7D0, CHostState__State_NewGameHook, reinterpret_cast<LPVOID*>(&CHostState__State_NewGame)); + ENABLER_CREATEHOOK( + hook, (char*)baseAddress + 0x16E520, CHostState__State_ChangeLevelMPHook, reinterpret_cast<LPVOID*>(&CHostState__State_ChangeLevelMP)); + ENABLER_CREATEHOOK( + hook, (char*)baseAddress + 0x16E640, CHostState__State_GameShutdownHook, reinterpret_cast<LPVOID*>(&CHostState__State_GameShutdown)); +})
\ No newline at end of file diff --git a/NorthstarDedicatedTest/hoststate.h b/NorthstarDedicatedTest/hoststate.h new file mode 100644 index 00000000..4861ac7e --- /dev/null +++ b/NorthstarDedicatedTest/hoststate.h @@ -0,0 +1,45 @@ +#pragma once + +// use the R2 namespace for game funxcs +namespace R2 +{ + enum class HostState_t + { + HS_NEW_GAME = 0, + HS_LOAD_GAME, + HS_CHANGE_LEVEL_SP, + HS_CHANGE_LEVEL_MP, + HS_RUN, + HS_GAME_SHUTDOWN, + HS_SHUTDOWN, + HS_RESTART, + }; + + struct CHostState + { + public: + HostState_t m_iCurrentState; + HostState_t m_iNextState; + + float m_vecLocation[3]; + float m_angLocation[3]; + + char m_levelName[32]; + char m_mapGroupName[32]; + char m_landmarkName[32]; + char m_saveName[32]; + float m_flShortFrameTime; // run a few one-tick frames to avoid large timesteps while loading assets + + bool m_activeGame; + bool m_bRememberLocation; + bool m_bBackgroundLevel; + bool m_bWaitingForConnection; + bool m_bLetToolsOverrideLoadGameEnts; // During a load game, this tells Foundry to override ents that are selected in Hammer. + bool m_bSplitScreenConnect; + bool m_bGameHasShutDownAndFlushedMemory; // This is false once we load a map into memory, and set to true once the map is unloaded + // and all memory flushed + bool m_bWorkshopMapDownloadPending; + }; + + extern CHostState* g_pHostState; +} // namespace R2
\ No newline at end of file diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index a87dfb20..f8e9a6fa 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -7,6 +7,7 @@ #include "hookutils.h" #include "serverauthentication.h" #include "gameutils.h" +#include "hoststate.h" #include "tier0.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" @@ -17,8 +18,6 @@ #include <cstring> #include <regex> #include "version.h" -// NOTE for anyone reading this: we used to use httplib for requests here, but it had issues, so we're moving to curl now for masterserver -// requests so httplib is used exclusively for server stuff now ConVar* Cvar_ns_masterserver_hostname; ConVar* Cvar_ns_report_server_to_masterserver; @@ -36,18 +35,6 @@ ConVar* Cvar_hostport; MasterServerManager* g_MasterServerManager; -typedef void (*CHostState__State_NewGameType)(CHostState* hostState); -CHostState__State_NewGameType CHostState__State_NewGame; - -typedef void (*CHostState__State_ChangeLevelMPType)(CHostState* hostState); -CHostState__State_ChangeLevelMPType CHostState__State_ChangeLevelMP; - -typedef void (*CHostState__State_ChangeLevelSPType)(CHostState* hostState); -CHostState__State_ChangeLevelSPType CHostState__State_ChangeLevelSP; - -typedef void (*CHostState__State_GameShutdownType)(CHostState* hostState); -CHostState__State_GameShutdownType CHostState__State_GameShutdown; - // Convert a hex digit char to integer. inline int hctod(char c) { @@ -168,7 +155,7 @@ size_t CurlWriteToStringBufferCallback(char* contents, size_t size, size_t nmemb return size * nmemb; } -void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* originToken) +void MasterServerManager::AuthenticateOriginWithMasterServer(const char* uid, const char* originToken) { if (m_bOriginAuthWithMasterServerInProgress) return; @@ -519,7 +506,7 @@ void MasterServerManager::RequestMainMenuPromos() requestThread.detach(); } -void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken) +void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* playerToken) { // dont wait, just stop if we're trying to do 2 auth requests at once if (m_bAuthenticatingWithGameServer) @@ -645,7 +632,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken requestThread.detach(); } -void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, char* serverId, char* password) +void MasterServerManager::AuthenticateWithServer(const char* uid, const char* playerToken, const char* serverId, const char* password) { // dont wait, just stop if we're trying to do 2 auth requests at once if (m_bAuthenticatingWithGameServer) @@ -767,7 +754,14 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c } void MasterServerManager::AddSelfToServerList( - int port, int authPort, char* name, char* description, char* map, char* playlist, int maxPlayers, char* password) + int port, + int authPort, + const char* name, + const char* description, + const char* map, + const char* playlist, + int maxPlayers, + const char* password) { if (!Cvar_ns_report_server_to_masterserver->GetBool()) return; @@ -917,7 +911,7 @@ void MasterServerManager::AddSelfToServerList( { char* escapedNameNew = curl_easy_escape(curl, g_MasterServerManager->m_sUnicodeServerName.c_str(), NULL); char* escapedDescNew = curl_easy_escape(curl, g_MasterServerManager->m_sUnicodeServerDesc.c_str(), NULL); - char* escapedMapNew = curl_easy_escape(curl, g_pHostState->m_levelName, NULL); + char* escapedMapNew = curl_easy_escape(curl, R2::g_pHostState->m_levelName, NULL); char* escapedPlaylistNew = curl_easy_escape(curl, R2::GetCurrentPlaylistName(), NULL); char* escapedPasswordNew = curl_easy_escape(curl, Cvar_ns_server_password->GetString(), NULL); @@ -1016,7 +1010,7 @@ void MasterServerManager::AddSelfToServerList( requestThread.detach(); } -void MasterServerManager::UpdateServerMapAndPlaylist(char* map, char* playlist, int maxPlayers) +void MasterServerManager::UpdateServerMapAndPlaylist(const char* map, const char* playlist, int maxPlayers) { // dont call this if we don't have a server id if (!*m_sOwnServerId) @@ -1106,7 +1100,7 @@ void MasterServerManager::UpdateServerPlayerCount(int playerCount) requestThread.detach(); } -void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata, size_t pdataSize) +void MasterServerManager::WritePlayerPersistentData(const char* playerId, const char* pdata, size_t pdataSize) { // still call this if we don't have a server id, since lobbies that aren't port forwarded need to be able to call it m_bSavingPersistentData = true; @@ -1204,95 +1198,6 @@ void ConCommand_ns_fetchservers(const CCommand& args) g_MasterServerManager->RequestServerList(); } -// todo: this should be somewhere else, not masterserver code - -void CHostState__State_NewGameHook(CHostState* hostState) -{ - 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_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame) - R2::SetCurrentPlaylist("tdm"); - - // 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)) - { - Cbuf_AddText(Cbuf_GetCurrentPlayer(), "net_data_block_enabled 1", cmd_source_t::kCommandSrcCode); - Cbuf_Execute(); - } - - double dStartTime = Tier0::Plat_FloatTime(); - CHostState__State_NewGame(hostState); - spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); - - int maxPlayers = 6; - const char* maxPlayersVar = R2::GetCurrentPlaylistVar("max_players", false); - if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this - maxPlayers = std::stoi(maxPlayersVar); - - // Copy new server name cvar to source - Cvar_hostname->SetValue(Cvar_ns_server_name->GetString()); - - g_MasterServerManager->AddSelfToServerList( - Cvar_hostport->GetInt(), - Cvar_ns_player_auth_port->GetInt(), - (char*)Cvar_ns_server_name->GetString(), - (char*)Cvar_ns_server_desc->GetString(), - hostState->m_levelName, - (char*)R2::GetCurrentPlaylistName(), - maxPlayers, - (char*)Cvar_ns_server_password->GetString()); - g_ServerAuthenticationManager->StartPlayerAuthServer(); - g_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame = false; -} - -void CHostState__State_ChangeLevelMPHook(CHostState* hostState) -{ - int maxPlayers = 6; - const char* maxPlayersVar = R2::GetCurrentPlaylistVar("max_players", false); - if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this - maxPlayers = std::stoi(maxPlayersVar); - - // 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)) - { - Cbuf_AddText(Cbuf_GetCurrentPlayer(), "net_data_block_enabled 1", cmd_source_t::kCommandSrcCode); - Cbuf_Execute(); - } - - g_MasterServerManager->UpdateServerMapAndPlaylist(hostState->m_levelName, (char*)R2::GetCurrentPlaylistName(), maxPlayers); - - double dStartTime = Tier0::Plat_FloatTime(); - CHostState__State_ChangeLevelMP(hostState); - spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); -} - -void CHostState__State_ChangeLevelSPHook(CHostState* hostState) -{ - // is this even called? genuinely i don't think so - // from what i can tell, it's not called on mp=>sp change or sp=>sp change - // so idk it's fucked - - int maxPlayers = 6; - const char* maxPlayersVar = R2::GetCurrentPlaylistVar("max_players", false); - if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this - maxPlayers = std::stoi(maxPlayersVar); - - g_MasterServerManager->UpdateServerMapAndPlaylist(hostState->m_levelName, (char*)R2::GetCurrentPlaylistName(), maxPlayers); - CHostState__State_ChangeLevelSP(hostState); -} - -void CHostState__State_GameShutdownHook(CHostState* hostState) -{ - g_MasterServerManager->RemoveSelfFromServerList(); - g_ServerAuthenticationManager->StopPlayerAuthServer(); - - CHostState__State_GameShutdown(hostState); -} - MasterServerManager::MasterServerManager() : m_pendingConnectionInfo {}, m_sOwnServerId {""}, m_sOwnClientAuthToken {""} {} ON_DLL_LOAD_RELIESON("engine.dll", MasterServer, ConCommand, [](HMODULE baseAddress) @@ -1318,23 +1223,4 @@ ON_DLL_LOAD_RELIESON("engine.dll", MasterServer, ConCommand, [](HMODULE baseAddr Cvar_hostport = (ConVar*)((char*)baseAddress + 0x13FA6070); RegisterConCommand("ns_fetchservers", ConCommand_ns_fetchservers, "Fetch all servers from the masterserver", FCVAR_CLIENTDLL); - - HookEnabler hook; - ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x16E7D0, CHostState__State_NewGameHook, reinterpret_cast<LPVOID*>(&CHostState__State_NewGame)); - ENABLER_CREATEHOOK( - hook, - (char*)baseAddress + 0x16E520, - CHostState__State_ChangeLevelMPHook, - reinterpret_cast<LPVOID*>(&CHostState__State_ChangeLevelMP)); - ENABLER_CREATEHOOK( - hook, - (char*)baseAddress + 0x16E5D0, - CHostState__State_ChangeLevelSPHook, - reinterpret_cast<LPVOID*>(&CHostState__State_ChangeLevelSP)); - ENABLER_CREATEHOOK( - hook, - (char*)baseAddress + 0x16E640, - CHostState__State_GameShutdownHook, - reinterpret_cast<LPVOID*>(&CHostState__State_GameShutdown)); })
\ No newline at end of file diff --git a/NorthstarDedicatedTest/masterserver.h b/NorthstarDedicatedTest/masterserver.h index ff727878..dcf6fb66 100644 --- a/NorthstarDedicatedTest/masterserver.h +++ b/NorthstarDedicatedTest/masterserver.h @@ -3,6 +3,20 @@ #include <WinSock2.h> #include <string> #include <cstring> + +extern ConVar* Cvar_ns_masterserver_hostname; +extern ConVar* Cvar_ns_report_server_to_masterserver; +extern ConVar* Cvar_ns_report_sp_server_to_masterserver; + +extern ConVar* Cvar_ns_server_name; +extern ConVar* Cvar_ns_server_desc; +extern ConVar* Cvar_ns_server_password; + +extern ConVar* Cvar_ns_curl_log_enable; + +extern ConVar* Cvar_hostname; +extern ConVar* Cvar_hostport; + struct RemoteModInfo { public: @@ -114,14 +128,21 @@ class MasterServerManager void ClearServerList(); void RequestServerList(); void RequestMainMenuPromos(); - void AuthenticateOriginWithMasterServer(char* uid, char* originToken); - void AuthenticateWithOwnServer(char* uid, char* playerToken); - void AuthenticateWithServer(char* uid, char* playerToken, char* serverId, char* password); - void - AddSelfToServerList(int port, int authPort, char* name, char* description, char* map, char* playlist, int maxPlayers, char* password); - void UpdateServerMapAndPlaylist(char* map, char* playlist, int playerCount); + void AuthenticateOriginWithMasterServer(const char* uid, const char* originToken); + void AuthenticateWithOwnServer(const char* uid, const char* playerToken); + void AuthenticateWithServer(const char* uid, const char* playerToken, const char* serverId, const char* password); + void AddSelfToServerList( + int port, + int authPort, + const char* name, + const char* description, + const char* map, + const char* playlist, + int maxPlayers, + const char* password); + void UpdateServerMapAndPlaylist(const char* map, const char* playlist, int playerCount); void UpdateServerPlayerCount(int playerCount); - void WritePlayerPersistentData(char* playerId, char* pdata, size_t pdataSize); + void WritePlayerPersistentData(const char* playerId, const char* pdata, size_t pdataSize); void RemoveSelfFromServerList(); }; std::string unescape_unicode(const std::string& str); diff --git a/NorthstarDedicatedTest/misccommands.cpp b/NorthstarDedicatedTest/misccommands.cpp index 51891a07..d74e6e5a 100644 --- a/NorthstarDedicatedTest/misccommands.cpp +++ b/NorthstarDedicatedTest/misccommands.cpp @@ -3,6 +3,7 @@ #include "concommand.h" #include "gameutils.h" #include "playlist.h" +#include "hoststate.h" #include "masterserver.h" #include "serverauthentication.h" #include "squirrel.h" @@ -18,8 +19,8 @@ void AddMiscConCommands() if (arg.ArgC() < 2) return; - g_pHostState->m_iNextState = HS_NEW_GAME; - strncpy(g_pHostState->m_levelName, arg.Arg(1), sizeof(g_pHostState->m_levelName)); + R2::g_pHostState->m_iNextState = R2::HostState_t::HS_NEW_GAME; + strncpy(R2::g_pHostState->m_levelName, arg.Arg(1), sizeof(R2::g_pHostState->m_levelName)); }); MAKE_CONCMD( @@ -54,8 +55,8 @@ void AddMiscConCommands() // this won't set playlist correctly on remote clients, don't think they can set playlist until they've left which sorta // fucks things should maybe set this in HostState_NewGame? R2::SetCurrentPlaylist("tdm"); - strcpy(g_pHostState->m_levelName, "mp_lobby"); - g_pHostState->m_iNextState = HS_NEW_GAME; + strcpy(R2::g_pHostState->m_levelName, "mp_lobby"); + R2::g_pHostState->m_iNextState = R2::HostState_t::HS_NEW_GAME; } }); }
\ No newline at end of file diff --git a/NorthstarDedicatedTest/playlist.h b/NorthstarDedicatedTest/playlist.h index 2ca1985f..fd5949e1 100644 --- a/NorthstarDedicatedTest/playlist.h +++ b/NorthstarDedicatedTest/playlist.h @@ -1,4 +1,6 @@ #pragma once + +// use the R2 namespace for game funcs namespace R2 { typedef const char* (*GetCurrentPlaylistNameType)(); diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp index 3660eada..9ac20653 100644 --- a/NorthstarDedicatedTest/serverauthentication.cpp +++ b/NorthstarDedicatedTest/serverauthentication.cpp @@ -7,6 +7,7 @@ #include "masterserver.h" #include "httplib.h" #include "gameutils.h" +#include "hoststate.h" #include "bansystem.h" #include "miscserverscript.h" #include "concommand.h" @@ -499,7 +500,7 @@ char __fastcall CNetChan___ProcessMessagesHook(void* self, void* buf) char ret = CNetChan___ProcessMessages(self, buf); // check processing limits, unless we're in a level transition - if (g_pHostState->m_iCurrentState == HostState_t::HS_RUN && ThreadInServerFrameThread()) + if (R2::g_pHostState->m_iCurrentState == R2::HostState_t::HS_RUN && ThreadInServerFrameThread()) { // player that sent the message void* sender = *(void**)((char*)self + 368); |