aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest/dedicated.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDedicatedTest/dedicated.cpp')
-rw-r--r--NorthstarDedicatedTest/dedicated.cpp329
1 files changed, 0 insertions, 329 deletions
diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp
deleted file mode 100644
index 5099a6d2..00000000
--- a/NorthstarDedicatedTest/dedicated.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-#include "pch.h"
-#include "dedicated.h"
-#include "hookutils.h"
-#include "gameutils.h"
-#include "serverauthentication.h"
-#include "masterserver.h"
-
-bool IsDedicated()
-{
- static bool result = strstr(GetCommandLineA(), "-dedicated");
- return result;
-}
-
-// CDedidcatedExports defs
-struct CDedicatedExports; // forward declare
-
-typedef void (*DedicatedSys_PrintfType)(CDedicatedExports* dedicated, const char* msg);
-typedef void (*DedicatedRunServerType)(CDedicatedExports* dedicated);
-
-// would've liked to just do this as a class but have not been able to get it to work
-struct CDedicatedExports
-{
- void* vtable; // because it's easier, we just set this to &this, since CDedicatedExports has no props we care about other than funcs
-
- char unused[56];
-
- DedicatedSys_PrintfType Sys_Printf;
- DedicatedRunServerType RunServer;
-};
-
-void Sys_Printf(CDedicatedExports* dedicated, const char* msg)
-{
- spdlog::info("[DEDICATED PRINT] {}", msg);
-}
-
-typedef void (*CHostState__InitType)(CHostState* self);
-
-void RunServer(CDedicatedExports* dedicated)
-{
- spdlog::info("CDedicatedExports::RunServer(): starting");
- spdlog::info(CommandLine()->GetCmdLine());
-
- // initialise engine
- g_pEngine->Frame();
-
- // add +map if not 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 (!CommandLine()->CheckParm("+map"))
- CommandLine()->AppendParm("+map", g_pCVar->FindVar("match_defaultMap")->GetString());
-
- // 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
- SetCurrentPlaylist(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");
-
- // main loop
- double frameTitle = 0;
- while (g_pEngine->m_nQuitting == EngineQuitState::QUIT_NOTQUITTING)
- {
- double frameStart = Plat_FloatTime();
- g_pEngine->Frame();
-
- // only update the title after at least 500ms since the last update
- if ((frameStart - frameTitle) > 0.5)
- {
- frameTitle = frameStart;
-
- // this way of getting playercount/maxplayers honestly really sucks, but not got any other methods of doing it rn
- const char* maxPlayers = GetCurrentPlaylistVar("max_players", false);
- if (!maxPlayers)
- maxPlayers = "6";
-
- SetConsoleTitleA(fmt::format(
- "{} - {} {}/{} players ({})",
- g_MasterServerManager->ns_auth_srvName,
- g_pHostState->m_levelName,
- g_ServerAuthenticationManager->m_additionalPlayerData.size(),
- maxPlayers,
- GetCurrentPlaylistName())
- .c_str());
- }
-
- std::this_thread::sleep_for(std::chrono::duration<double, std::ratio<1>>(
- Cvar_base_tickinterval_mp->GetFloat() - fmin(Plat_FloatTime() - frameStart, 0.25)));
- }
-}
-
-typedef bool (*IsGameActiveWindowType)();
-IsGameActiveWindowType IsGameActiveWindow;
-bool IsGameActiveWindowHook()
-{
- return true;
-}
-
-HANDLE consoleInputThreadHandle = NULL;
-
-DWORD WINAPI ConsoleInputThread(PVOID pThreadParameter)
-{
- while (!g_pEngine || !g_pHostState || g_pHostState->m_iCurrentState != HostState_t::HS_RUN)
- Sleep(1000);
-
- // Bind stdin to receive console input.
- FILE* fp = nullptr;
- freopen_s(&fp, "CONIN$", "r", stdin);
-
- spdlog::info("Ready to receive console commands.");
-
- {
- // Process console input
- std::string input;
- while (g_pEngine && g_pEngine->m_nQuitting == EngineQuitState::QUIT_NOTQUITTING && std::getline(std::cin, input))
- {
- input += "\n";
- Cbuf_AddText(Cbuf_GetCurrentPlayer(), input.c_str(), cmd_source_t::kCommandSrcCode);
- }
- }
-
- return 0;
-}
-
-#include "NSMem.h"
-void InitialiseDedicated(HMODULE engineAddress)
-{
- spdlog::info("InitialiseDedicated");
-
- uintptr_t ea = (uintptr_t)engineAddress;
-
- {
- // Host_Init
- // prevent a particle init that relies on client dll
- NSMem::NOP(ea + 0x156799, 5);
- }
-
- {
- // CModAppSystemGroup::Create
- // force the engine into dedicated mode by changing the first comparison to IsServerOnly to an assignment
- auto ptr = ea + 0x1C4EBD;
-
- // cmp => mov
- NSMem::BytePatch(ptr + 1, "C6 87");
-
- // 00 => 01
- NSMem::BytePatch(ptr + 7, "01");
- }
-
- {
- // Some init that i'm not sure of that crashes
- // nop the call to it
- NSMem::NOP(ea + 0x156A63, 5);
- }
-
- {
- // runframeserver
- // nop some access violations
- NSMem::NOP(ea + 0x159819, 17);
- }
-
- {
- NSMem::NOP(ea + 0x156B4C, 7);
-
- // previously patched these, took me a couple weeks to figure out they were the issue
- // removing these will mess up register state when this function is over, so we'll write HS_RUN to the wrong address
- // so uhh, don't do that
- // NSMem::NOP(ea + 0x156B4C + 7, 8);
-
- NSMem::NOP(ea + 0x156B4C + 15, 9);
- }
-
- {
- // HostState_State_NewGame
- // nop an access violation
- NSMem::NOP(ea + 0xB934C, 9);
- }
-
- {
- // CEngineAPI::Connect
- // remove call to Shader_Connect
- NSMem::NOP(ea + 0x1C4D7D, 5);
- }
-
- // currently does not work, crashes stuff, likely gotta keep this here
- //{
- // // CEngineAPI::Connect
- // // remove calls to register ui rpak asset types
- // NSMem::NOP(ea + 0x1C4E07, 5);
- //}
-
- {
- // Host_Init
- // remove call to ui loading stuff
- NSMem::NOP(ea + 0x156595, 5);
- }
-
- {
- // some function that gets called from RunFrameServer
- // nop a function that makes requests to stryder, this will eventually access violation if left alone and isn't necessary anyway
- NSMem::NOP(ea + 0x15A0BB, 5);
- }
-
- {
- // RunFrameServer
- // nop a function that access violations
- NSMem::NOP(ea + 0x159BF3, 5);
- }
-
- {
- // func that checks if origin is inited
- // always return 1
- NSMem::BytePatch(
- ea + 0x183B70,
- {
- 0xB0,
- 0x01, // mov al,01
- 0xC3 // ret
- });
- }
-
- {
- // HostState_State_ChangeLevel
- // nop clientinterface call
- NSMem::NOP(ea + 0x1552ED, 16);
- }
-
- {
- // HostState_State_ChangeLevel
- // nop clientinterface call
- NSMem::NOP(ea + 0x155363, 16);
- }
-
- // note: previously had DisableDedicatedWindowCreation patches here, but removing those rn since they're all shit and unstable and bad
- // and such check commit history if any are needed for reimplementation
- {
- // IVideoMode::CreateGameWindow
- // nop call to ShowWindow
- NSMem::NOP(ea + 0x1CD146, 5);
- }
-
- CDedicatedExports* dedicatedExports = new CDedicatedExports;
- dedicatedExports->vtable = dedicatedExports;
- dedicatedExports->Sys_Printf = Sys_Printf;
- dedicatedExports->RunServer = RunServer;
-
- CDedicatedExports** exports = (CDedicatedExports**)((char*)engineAddress + 0x13F0B668);
- *exports = dedicatedExports;
-
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)engineAddress + 0x1CDC80, &IsGameActiveWindowHook, reinterpret_cast<LPVOID*>(&IsGameActiveWindow));
-
- // extra potential patches:
- // nop engine.dll+1c67d1 and +1c67d8 to skip videomode creategamewindow
- // also look into launcher.dll+d381, seems to cause renderthread to get made
- // this crashes HARD if no window which makes sense tbh
- // also look into materialsystem + 5B344 since it seems to be the base of all the renderthread stuff
-
- // big note: datatable gets registered in window creation
- // make sure it still gets registered
-
- // add cmdline args that are good for dedi
- CommandLine()->AppendParm("-nomenuvid", 0);
- CommandLine()->AppendParm("-nosound", 0);
- CommandLine()->AppendParm("-windowed", 0);
- CommandLine()->AppendParm("-nomessagebox", 0);
- CommandLine()->AppendParm("+host_preload_shaders", "0");
- CommandLine()->AppendParm("+net_usesocketsforloopback", "1");
-
- // Disable Quick Edit mode to reduce chance of user unintentionally hanging their server by selecting something.
- if (!CommandLine()->CheckParm("-bringbackquickedit"))
- {
- HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
- DWORD mode = 0;
-
- if (GetConsoleMode(stdIn, &mode))
- {
- if (mode & ENABLE_QUICK_EDIT_MODE)
- {
- mode &= ~ENABLE_QUICK_EDIT_MODE;
- mode &= ~ENABLE_MOUSE_INPUT;
-
- mode |= ENABLE_PROCESSED_INPUT;
-
- SetConsoleMode(stdIn, mode);
- }
- }
- }
- else
- spdlog::info("Quick Edit enabled by user request");
-
- // create console input thread
- if (!CommandLine()->CheckParm("-noconsoleinput"))
- consoleInputThreadHandle = CreateThread(0, 0, ConsoleInputThread, 0, 0, NULL);
- else
- spdlog::info("Console input disabled by user request");
-}
-
-void InitialiseDedicatedOrigin(HMODULE baseAddress)
-{
- // disable origin on dedicated
- // for any big ea lawyers, this can't be used to play the game without origin, game will throw a fit if you try to do anything without
- // an origin id as a client for dedi it's fine though, game doesn't care if origin is disabled as long as there's only a server
-
- NSMem::BytePatch(
- (uintptr_t)GetProcAddress(GetModuleHandleA("tier0.dll"), "Tier0_InitOrigin"),
- {
- 0xC3 // ret
- });
-}
-
-typedef void (*PrintFatalSquirrelErrorType)(void* sqvm);
-PrintFatalSquirrelErrorType PrintFatalSquirrelError;
-void PrintFatalSquirrelErrorHook(void* sqvm)
-{
- PrintFatalSquirrelError(sqvm);
- g_pEngine->m_nQuitting = EngineQuitState::QUIT_TODESKTOP;
-}
-
-void InitialiseDedicatedServerGameDLL(HMODULE baseAddress)
-{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, baseAddress + 0x794D0, &PrintFatalSquirrelErrorHook, reinterpret_cast<LPVOID*>(&PrintFatalSquirrelError));
-} \ No newline at end of file