diff options
author | BobTheBob <32057864+BobTheBob9@users.noreply.github.com> | 2022-10-17 23:26:07 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-17 23:26:07 +0100 |
commit | 841881af9ea6ec73b1d505d5a8f7c1f766273724 (patch) | |
tree | 91feb40fe810984b59d2d2da440e289370b0a137 /NorthstarDLL/dedicated.cpp | |
parent | dc0934d29caacc8da1e7df8b775d24b4e99c381c (diff) | |
download | NorthstarLauncher-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.cpp | 286 |
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 + } } |