aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL/dedicated.cpp
diff options
context:
space:
mode:
authorBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2022-10-17 23:26:07 +0100
committerGitHub <noreply@github.com>2022-10-17 23:26:07 +0100
commit841881af9ea6ec73b1d505d5a8f7c1f766273724 (patch)
tree91feb40fe810984b59d2d2da440e289370b0a137 /NorthstarDLL/dedicated.cpp
parentdc0934d29caacc8da1e7df8b775d24b4e99c381c (diff)
downloadNorthstarLauncher-841881af9ea6ec73b1d505d5a8f7c1f766273724.tar.gz
NorthstarLauncher-841881af9ea6ec73b1d505d5a8f7c1f766273724.zip
big refactor (#171)v1.10.0-rc1
* use in-file macros rather than global funcs for registering dll load callbacks * move more things to macros * fix debug crashes * move sqvm funcs to sq managers * get rid of context file * refactor some squirrel stuff and ingame compilation error message * move tier0 and playlist funcs to namespaces * uiscript_reset concommand: don't loop forever if compilation fails * improve showing console for ui script compile errors * standardise concommand func naming in c++ * use lambdas for dll load callbacks so intellisense shits itself less * use cvar change callbacks for unescaping ns_server_name and ns_server_desc * add proper helpstrings to masterserver cvars * add cvar help and find * allow parsing of convar flags from string * normalise mod fs paths to be lowercase * move hoststate to its own file and add host_init hooks * better IsFlagSet def * replace files in ReadFromCache * rename g_ModManager to g_pModManager * formatting changes * make cvar print work on dedi, move demo fix stuff, add findflags * add proper map autocompletes and maps command * formatting changes * separate gameutils into multiple r2 headers * Update keyvalues.cpp * move sqvm funcs into wrappers in the manager class * remove unnecessary header files * lots of cleanup and starting moving to new hooking macros * update more stuff to new hook macros * rename project folder (:tf: commit log) * fix up postbuild commands to use relative dir * almost fully replaced hooking lib * completely remove old hooking * add nsprefix because i forgot to include it * move exploit prevention and limits code out of serverauthentication, and have actual defs for CBasePlayer * use modular ServerPresence system for registering servers * add new memory lib * accidentally pushed broke code oops * lots of stuff idk * implement some more prs * improve rpakfilesystem * fix line endings on vcxproj * Revert "fix line endings on vcxproj" This reverts commit 4ff7d022d2602c2dba37beba8b8df735cf5cd7d9. * add more prs * i swear i committed these how are they not there * Add ability to load Datatables from files (#238) * first version of kinda working custom datatables * Fix copy error * Finish custom datatables * Fix Merge * Fix line endings * Add fallback to rpak when ns_prefere_datatable_from_disk is true * fix typo * Bug fixess * Fix Function Registration hook * Set convar value * Fix Client and Ui VM * enable server auth with ms agian * Add Filters * FIx unused import * Merge remote-tracking branch 'upsteam/bobs-big-refactor-pr' into datatables Co-authored-by: RoyalBlue1 <realEmail@veryRealURL.com> * Add some changes from main to refactor (#243) * Add PR template * Update CI folder location * Delete startup args txt files * Fix line endings (hopefully) (#244) * Fix line endings (hopefully) * Fix more line endings * Update refactor (#250) * Add PR template * Update CI folder location * Delete startup args txt files * Add editorconfig file (#246) * Add editorconfig file It's a cross-editor compatible config file that defines certain editor behaviour (e.g. adding/removing newline at end of file) It is supported by major editors like Visual Studio (Code) and by version control providers like GitHub. Should end the constant adding/removing of final newline in PRs * More settings - unicode by default - trim newlines - use tabs for indentation (ugh) * Ignore folder rename (#245) * Hot reload banlist on player join (#233) * added banlist hotreload * fix formatting * didnt append, cleared whole file oopsie * unfuckedunban not rewriting file * fixed not checking for new line Co-authored-by: ScureX <47725553+ScureX@users.noreply.github.com> * Refactor cleanup (#256) * Fix indentation * Fix path in clang-format command in readme * Refactor cleanup (some formatting fixes) (#257) * Fix some formatting * More formatting fixes * add scriptdatatable.cpp rewrite * Some formatting fixes (#260) * More formatting stuff (#261) * various formatting changes and fixes * Fix changed icon (#264) * clang format, fix issues with server registration and rpak loading * fix more formatting * update postbuild step * set launcher directory and error on fail creating log files * change some stuff in exploitfixes * only unrestrict dev commands when commandline flag is present * fix issues with cvar flag commit * fixup command flags better and reformat * bring up to date with main * fixup formatting * improve cvar flag fixup and remove temp thing from findflags * set serverfilter better * avoid ptr decay when setting auth token * add more entity functions * Fix the MS server registration issues. (#285) * Port ms presence reporter to std::async * Fix crash due to std::optional being assigned nullptr. * Fix formatting. * Wait 20 seconds if MS returns DUPLICATE_SERVER. * Change PERSISTENCE_MAX_SIZE to fix player authentication (#287) The size check added in the refactor was incorrect: - 56306: expected pdata size based on the pdef - 512: allowance for trailing junk (r2 adds 137 bytes of trailing junk) - 100: for some wiggle room Co-Authored-By: pg9182 <96569817+pg9182@users.noreply.github.com> * change miscserverscript to use actual entity arguments rather than player index jank * Fix token clearing hook (#290) A certain someone forgot to put an `0x` in front of their hex number, meaning the offset is wrong. This would cause token to be leaked again Co-authored-by: Maya <malte.hoermeyer@web.de> Co-authored-by: RoyalBlue1 <realEmail@veryRealURL.com> Co-authored-by: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Co-authored-by: ScureX <47725553+ScureX@users.noreply.github.com> Co-authored-by: Erlite <ys.aameziane@gmail.com> Co-authored-by: Emma Miler <emma.pi@protonmail.com> Co-authored-by: pg9182 <96569817+pg9182@users.noreply.github.com>
Diffstat (limited to 'NorthstarDLL/dedicated.cpp')
-rw-r--r--NorthstarDLL/dedicated.cpp286
1 files changed, 125 insertions, 161 deletions
diff --git a/NorthstarDLL/dedicated.cpp b/NorthstarDLL/dedicated.cpp
index e6394aee..251e2437 100644
--- a/NorthstarDLL/dedicated.cpp
+++ b/NorthstarDLL/dedicated.cpp
@@ -1,9 +1,16 @@
#include "pch.h"
#include "dedicated.h"
-#include "hookutils.h"
-#include "gameutils.h"
+#include "tier0.h"
+#include "playlist.h"
+#include "r2engine.h"
+#include "hoststate.h"
#include "serverauthentication.h"
#include "masterserver.h"
+#include "printcommand.h"
+
+AUTOHOOK_INIT()
+
+using namespace R2;
bool IsDedicatedServer()
{
@@ -33,32 +40,23 @@ void Sys_Printf(CDedicatedExports* dedicated, const char* msg)
spdlog::info("[DEDICATED SERVER] {}", msg);
}
-typedef void (*CHostState__InitType)(CHostState* self);
-
void RunServer(CDedicatedExports* dedicated)
{
spdlog::info("CDedicatedExports::RunServer(): starting");
- spdlog::info(CommandLine()->GetCmdLine());
+ spdlog::info(Tier0::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());
+ if (!Tier0::CommandLine()->CheckParm("+map"))
+ Tier0::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);
+ // re-run commandline
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");
@@ -66,43 +64,31 @@ void RunServer(CDedicatedExports* dedicated)
double frameTitle = 0;
while (g_pEngine->m_nQuitting == EngineQuitState::QUIT_NOTQUITTING)
{
- double frameStart = Plat_FloatTime();
+ double frameStart = Tier0::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->m_sUnicodeServerName,
- 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)));
+ Cvar_base_tickinterval_mp->GetFloat() - fmin(Tier0::Plat_FloatTime() - frameStart, 0.25)));
}
}
-typedef bool (*IsGameActiveWindowType)();
-IsGameActiveWindowType IsGameActiveWindow;
-bool IsGameActiveWindowHook()
+// use server presence to update window title
+class DedicatedConsoleServerPresence : public ServerPresenceReporter
{
- return true;
-}
+ void ReportPresence(const ServerPresence* pServerPresence) override
+ {
+ SetConsoleTitleA(fmt::format(
+ "{} - {} {}/{} players ({})",
+ pServerPresence->m_sServerName,
+ pServerPresence->m_MapName,
+ pServerPresence->m_iPlayerCount,
+ pServerPresence->m_iMaxPlayers,
+ pServerPresence->m_PlaylistName)
+ .c_str());
+ }
+};
HANDLE consoleInputThreadHandle = NULL;
-
DWORD WINAPI ConsoleInputThread(PVOID pThreadParameter)
{
while (!g_pEngine || !g_pHostState || g_pHostState->m_iCurrentState != HostState_t::HS_RUN)
@@ -121,139 +107,106 @@ DWORD WINAPI ConsoleInputThread(PVOID pThreadParameter)
{
input += "\n";
Cbuf_AddText(Cbuf_GetCurrentPlayer(), input.c_str(), cmd_source_t::kCommandSrcCode);
+ TryPrintCvarHelpForCommand(input.c_str()); // this needs to be done on main thread, unstable in this one
}
}
return 0;
}
-#include "nsmem.h"
-void InitialiseDedicated(HMODULE engineAddress)
+// clang-format off
+AUTOHOOK(IsGameActiveWindow, engine.dll + 0x1CDC80,
+bool,, ())
+// clang-format on
+{
+ return true;
+}
+
+ON_DLL_LOAD_DEDI_RELIESON("engine.dll", DedicatedServer, ServerPresence, (CModule module))
{
spdlog::info("InitialiseDedicated");
- uintptr_t ea = (uintptr_t)engineAddress;
+ AUTOHOOK_DISPATCH_MODULE("engine.dll")
- {
- // Host_Init
- // prevent a particle init that relies on client dll
- NSMem::NOP(ea + 0x156799, 5);
- }
+ // Host_Init
+ // prevent a particle init that relies on client dll
+ module.Offset(0x156799).NOP(5);
+
+ // Host_Init
+ // don't call Key_Init to avoid loading some extra rsons from rpak (will be necessary to boot if we ever wanna disable rpaks entirely on
+ // dedi)
+ module.Offset(0x1565B0).NOP(5);
{
// CModAppSystemGroup::Create
// force the engine into dedicated mode by changing the first comparison to IsServerOnly to an assignment
- auto ptr = ea + 0x1C4EBD;
+ MemoryAddress base = module.Offset(0x1C4EBD);
// cmp => mov
- NSMem::BytePatch(ptr + 1, "C6 87");
+ base.Offset(1).Patch("C6 87");
// 00 => 01
- NSMem::BytePatch(ptr + 7, "01");
+ base.Offset(7).Patch("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);
+ // Some init that i'm not sure of that crashes
+ // nop the call to it
+ module.Offset(0x156A63).NOP(5);
- // 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);
+ // runframeserver
+ // nop some access violations
+ module.Offset(0x159819).NOP(17);
- NSMem::NOP(ea + 0x156B4C + 15, 9);
- }
+ module.Offset(0x156B4C).NOP(7);
- {
- // HostState_State_NewGame
- // nop an access violation
- NSMem::NOP(ea + 0xB934C, 9);
- }
+ // 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);
+ module.Offset(0x156B4C).Offset(15).NOP(9);
- {
- // CEngineAPI::Connect
- // remove call to Shader_Connect
- NSMem::NOP(ea + 0x1C4D7D, 5);
- }
+ // HostState_State_NewGame
+ // nop an access violation
+ module.Offset(0xB934C).NOP(9);
- // 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);
- //}
+ // CEngineAPI::Connect
+ // remove call to Shader_Connect
+ module.Offset(0x1C4D7D).NOP(5);
- {
- // Host_Init
- // remove call to ui loading stuff
- NSMem::NOP(ea + 0x156595, 5);
- }
+ // Host_Init
+ // remove call to ui loading stuff
+ module.Offset(0x156595).NOP(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);
- }
+ // 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
+ module.Offset(0x15A0BB).NOP(5);
- {
- // RunFrameServer
- // nop a function that access violations
- NSMem::NOP(ea + 0x159BF3, 5);
- }
+ // RunFrameServer
+ // nop a function that access violations
+ module.Offset(0x159BF3).NOP(5);
- {
- // func that checks if origin is inited
- // always return 1
- NSMem::BytePatch(
- ea + 0x183B70,
- {
- 0xB0,
- 0x01, // mov al,01
- 0xC3 // ret
- });
- }
+ // func that checks if origin is inited
+ // always return 1
+ module.Offset(0x183B70).Patch("B0 01 C3"); // mov al,01 ret
- {
- // HostState_State_ChangeLevel
- // nop clientinterface call
- NSMem::NOP(ea + 0x1552ED, 16);
- }
+ // HostState_State_ChangeLevel
+ // nop clientinterface call
+ module.Offset(0x1552ED).NOP(16);
- {
- // HostState_State_ChangeLevel
- // nop clientinterface call
- NSMem::NOP(ea + 0x155363, 16);
- }
+ // HostState_State_ChangeLevel
+ // nop clientinterface call
+ module.Offset(0x155363).NOP(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);
- }
+ // IVideoMode::CreateGameWindow
+ // nop call to ShowWindow
+ module.Offset(0x1CD146).NOP(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));
+ *module.Offset(0x13F0B668).As<CDedicatedExports**>() = dedicatedExports;
// extra potential patches:
// nop engine.dll+1c67d1 and +1c67d8 to skip videomode creategamewindow
@@ -265,15 +218,19 @@ void InitialiseDedicated(HMODULE engineAddress)
// 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");
+ Tier0::CommandLine()->AppendParm("-nomenuvid", 0);
+ Tier0::CommandLine()->AppendParm("-nosound", 0);
+ Tier0::CommandLine()->AppendParm("-windowed", 0);
+ Tier0::CommandLine()->AppendParm("-nomessagebox", 0);
+ Tier0::CommandLine()->AppendParm("+host_preload_shaders", "0");
+ Tier0::CommandLine()->AppendParm("+net_usesocketsforloopback", "1");
+
+ // use presence reporter for console title
+ DedicatedConsoleServerPresence* presenceReporter = new DedicatedConsoleServerPresence;
+ g_pServerPresence->AddPresenceReporter(presenceReporter);
// Disable Quick Edit mode to reduce chance of user unintentionally hanging their server by selecting something.
- if (!CommandLine()->CheckParm("-bringbackquickedit"))
+ if (!Tier0::CommandLine()->CheckParm("-bringbackquickedit"))
{
HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
@@ -295,35 +252,42 @@ void InitialiseDedicated(HMODULE engineAddress)
spdlog::info("Quick Edit enabled by user request");
// create console input thread
- if (!CommandLine()->CheckParm("-noconsoleinput"))
+ if (!Tier0::CommandLine()->CheckParm("-noconsoleinput"))
consoleInputThreadHandle = CreateThread(0, 0, ConsoleInputThread, 0, 0, NULL);
else
spdlog::info("Console input disabled by user request");
}
-void InitialiseDedicatedOrigin(HMODULE baseAddress)
+ON_DLL_LOAD_DEDI("tier0.dll", DedicatedServerOrigin, (CModule module))
{
// 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
- });
+ module.GetExport("Tier0_InitOrigin").Patch("C3");
}
-typedef void (*PrintFatalSquirrelErrorType)(void* sqvm);
-PrintFatalSquirrelErrorType PrintFatalSquirrelError;
-void PrintFatalSquirrelErrorHook(void* sqvm)
+// clang-format off
+AUTOHOOK(PrintSquirrelError, server.dll + 0x794D0,
+void, __fastcall, (void* sqvm))
+// clang-format on
{
- PrintFatalSquirrelError(sqvm);
- g_pEngine->m_nQuitting = EngineQuitState::QUIT_TODESKTOP;
+ PrintSquirrelError(sqvm);
+
+ // close dedicated server if a fatal error is hit
+ static ConVar* Cvar_fatal_script_errors = g_pCVar->FindVar("fatal_script_errors");
+ if (Cvar_fatal_script_errors->GetBool())
+ abort();
}
-void InitialiseDedicatedServerGameDLL(HMODULE baseAddress)
+ON_DLL_LOAD_DEDI("server.dll", DedicatedServerGameDLL, (CModule module))
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, baseAddress + 0x794D0, &PrintFatalSquirrelErrorHook, reinterpret_cast<LPVOID*>(&PrintFatalSquirrelError));
+ AUTOHOOK_DISPATCH_MODULE(server.dll)
+
+ if (Tier0::CommandLine()->CheckParm("-nopakdedi"))
+ {
+ module.Offset(0x6BA350).Patch("C3"); // dont load skins.rson from rpak if we don't have rpaks, as loading it will cause a crash
+ module.Offset(0x6BA300).Patch(
+ "B8 C8 00 00 00 C3"); // return 200 as the number of skins from server.dll + 6BA300, this is the normal value read from
+ // skins.rson and should be updated when we need it more modular
+ }
}