From e85a3eee190e623e1d6397b4460817170b7bfced Mon Sep 17 00:00:00 2001 From: BobTheBob9 Date: Wed, 17 Aug 2022 19:26:55 +0100 Subject: implement some more prs --- NorthstarDLL/buildainfile.cpp | 2 +- NorthstarDLL/dedicated.cpp | 23 ++++++++++++++++----- NorthstarDLL/exploitfixes.cpp | 24 +++++++++++++++++----- NorthstarDLL/masterserver.cpp | 39 +++++++++++++++++++++++++++++++++--- NorthstarDLL/masterserver.h | 1 + NorthstarDLL/printcommands.cpp | 2 +- NorthstarDLL/printmaps.cpp | 2 +- NorthstarDLL/r2engine.cpp | 2 ++ NorthstarDLL/r2engine.h | 2 ++ NorthstarDLL/rpakfilesystem.cpp | 14 +++++++------ NorthstarDLL/scriptserverbrowser.cpp | 9 +++++++++ NorthstarDLL/serverpresence.cpp | 13 +++++++++++- NorthstarDLL/serverpresence.h | 2 ++ NorthstarDLL/squirrel.cpp | 6 +++--- 14 files changed, 115 insertions(+), 26 deletions(-) diff --git a/NorthstarDLL/buildainfile.cpp b/NorthstarDLL/buildainfile.cpp index b759db66..d0397fce 100644 --- a/NorthstarDLL/buildainfile.cpp +++ b/NorthstarDLL/buildainfile.cpp @@ -182,7 +182,7 @@ ConVar* Cvar_ns_ai_dumpAINfileFromLoad; void DumpAINInfo(CAI_Network* aiNetwork) { - fs::path writePath(fmt::format("{}/maps/graphs", "r2")); + fs::path writePath(fmt::format("{}/maps/graphs", R2::g_pModName)); writePath /= R2::g_pHostState->m_levelName; writePath += ".ain"; diff --git a/NorthstarDLL/dedicated.cpp b/NorthstarDLL/dedicated.cpp index 5fd67c33..d8e2992e 100644 --- a/NorthstarDLL/dedicated.cpp +++ b/NorthstarDLL/dedicated.cpp @@ -107,7 +107,7 @@ 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 + TryPrintCvarHelpForCommand(input.c_str()); // this needs to be done on main thread, unstable in this one } } @@ -264,14 +264,27 @@ ON_DLL_LOAD_DEDI("tier0.dll", DedicatedServerOrigin, (CModule module)) module.GetExport("Tier0_InitOrigin").Patch("C3"); } -AUTOHOOK(PrintFatalSquirrelError, server.dll + 0x794D0, +AUTOHOOK(PrintSquirrelError, server.dll + 0x794D0, void, , (void* sqvm)) { - 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(); } ON_DLL_LOAD_DEDI("server.dll", DedicatedServerGameDLL, (CModule module)) { - AUTOHOOK_DISPATCH_MODULE("server.dll") + 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 + + } } diff --git a/NorthstarDLL/exploitfixes.cpp b/NorthstarDLL/exploitfixes.cpp index 8b5783d6..a5d377b4 100644 --- a/NorthstarDLL/exploitfixes.cpp +++ b/NorthstarDLL/exploitfixes.cpp @@ -8,8 +8,12 @@ AUTOHOOK_INIT() -ConVar* ns_exploitfixes_log; -#define SHOULD_LOG (ns_exploitfixes_log->m_Value.m_nValue > 0) +ConVar* Cvar_ns_exploitfixes_log; +ConVar* Cvar_ns_should_log_all_clientcommands; + +ConVar* Cvar_sv_cheats; + +#define SHOULD_LOG (Cvar_ns_exploitfixes_log->m_Value.m_nValue > 0) #define BLOCKED_INFO(s) \ ( \ [=]() -> bool \ @@ -323,16 +327,22 @@ INVALID_CMD: AUTOHOOK(IsRespawnMod, engine.dll + 0x1C6360, bool, __fastcall, (const char* pModName)) // 48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 85 C0 74 63 { + // somewhat temp, store the modname here, since we don't have a proper ptr to it rn + int iSize = strlen(pModName); + R2::g_pModName = new char[iSize + 1]; + strcpy(R2::g_pModName, pModName); + return (!strcmp("r2", pModName) || !strcmp("r1", pModName)) && !Tier0::CommandLine()->CheckParm("-norestrictservercommands"); } -// ratelimit stringcmds, and prevent remote clients from calling non-FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS commands +// ratelimit stringcmds, and prevent remote clients from calling commands that they shouldn't bool (*CCommand__Tokenize)(CCommand& self, const char* pCommandString, R2::cmd_source_t commandSource); AUTOHOOK(CGameClient__ExecuteStringCommand, engine.dll + 0x1022E0, bool, , (R2::CBaseClient* self, uint32_t unknown, const char* pCommandString)) { - static ConVar* Cvar_sv_cheats = R2::g_pCVar->FindVar("sv_cheats"); // doing this here is temp + if (Cvar_ns_should_log_all_clientcommands->GetBool()) + spdlog::info("player {} (UID: {}) sent command: \"{}\"", self->m_Name, self->m_UID, pCommandString); if (!g_pServerLimits->CheckStringCommandLimits(self)) { @@ -476,6 +486,10 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerExploitFixes, ConVar, (CModule module)) } } - ns_exploitfixes_log = + Cvar_ns_exploitfixes_log = new ConVar("ns_exploitfixes_log", "1", FCVAR_GAMEDLL, "Whether to log whenever ExploitFixes.cpp blocks/corrects something"); + Cvar_ns_should_log_all_clientcommands = + new ConVar("ns_should_log_all_clientcommands", "0", FCVAR_NONE, "Whether to log all clientcommands"); + + Cvar_sv_cheats = R2::g_pCVar->FindVar("sv_cheats"); } diff --git a/NorthstarDLL/masterserver.cpp b/NorthstarDLL/masterserver.cpp index 75f0bb4b..b83170b0 100644 --- a/NorthstarDLL/masterserver.cpp +++ b/NorthstarDLL/masterserver.cpp @@ -485,6 +485,12 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* { spdlog::error("Failed reading masterserver response: got fastify error response"); spdlog::error(readBuffer); + + if (authInfoJson["error"].HasMember("enum")) + m_sAuthFailureReason = authInfoJson["error"]["enum"].GetString(); + else + m_sAuthFailureReason = "No error message provided"; + goto REQUEST_END_CLEANUP; } @@ -631,6 +637,12 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl { spdlog::error("Failed reading masterserver response: got fastify error response"); spdlog::error(readBuffer); + + if (connectionInfoJson["error"].HasMember("enum")) + m_sAuthFailureReason = connectionInfoJson["error"]["enum"].GetString(); + else + m_sAuthFailureReason = "No error message provided"; + goto REQUEST_END_CLEANUP; } @@ -738,16 +750,27 @@ void MasterServerManager::WritePlayerPersistentData(const char* playerId, const class MasterServerPresenceReporter : public ServerPresenceReporter { + const int MAX_REGISTRATION_ATTEMPTS = 5; + + double m_bShouldTryRegisterServer; + int m_nNumRegistrationAttempts; + + void CreatePresence(const ServerPresence* pServerPresence) override + { + m_bShouldTryRegisterServer = true; + m_nNumRegistrationAttempts = 0; + } + void ReportPresence(const ServerPresence* pServerPresence) override { // make a copy of presence for multithreading purposes ServerPresence threadedPresence(pServerPresence); - if (!*g_pMasterServerManager->m_sOwnServerId) + if (!*g_pMasterServerManager->m_sOwnServerId || m_bShouldTryRegisterServer) { // add server std::thread addServerThread( - [threadedPresence] + [this, threadedPresence] { g_pMasterServerManager->m_sOwnServerId[0] = 0; g_pMasterServerManager->m_sOwnServerAuthToken[0] = 0; @@ -830,7 +853,14 @@ class MasterServerPresenceReporter : public ServerPresenceReporter { spdlog::error("Failed reading masterserver response: got fastify error response"); spdlog::error(readBuffer); - goto REQUEST_END_CLEANUP; + + if (serverAddedJson["error"].HasMember("enum") && !strcmp(serverAddedJson["error"]["enum"].GetString(), "DUPLICATE_SERVER")) + { + if (++m_nNumRegistrationAttempts == MAX_REGISTRATION_ATTEMPTS) + m_bShouldTryRegisterServer = false; + } + + goto REQUEST_END_CLEANUP_RETRY; } if (!serverAddedJson["success"].IsTrue()) @@ -865,6 +895,9 @@ class MasterServerPresenceReporter : public ServerPresenceReporter } REQUEST_END_CLEANUP: + m_bShouldTryRegisterServer = false; + + REQUEST_END_CLEANUP_RETRY: curl_easy_cleanup(curl); curl_mime_free(mime); }); diff --git a/NorthstarDLL/masterserver.h b/NorthstarDLL/masterserver.h index 856adaac..efa938cc 100644 --- a/NorthstarDLL/masterserver.h +++ b/NorthstarDLL/masterserver.h @@ -100,6 +100,7 @@ class MasterServerManager bool m_bNewgameAfterSelfAuth = false; bool m_bScriptAuthenticatingWithGameServer = false; bool m_bSuccessfullyAuthenticatedWithGameServer = false; + std::string m_sAuthFailureReason {}; bool m_bHasPendingConnectionInfo = false; RemoteServerConnectionInfo m_pendingConnectionInfo; diff --git a/NorthstarDLL/printcommands.cpp b/NorthstarDLL/printcommands.cpp index 8acf6262..605f7dce 100644 --- a/NorthstarDLL/printcommands.cpp +++ b/NorthstarDLL/printcommands.cpp @@ -145,7 +145,7 @@ void ConCommand_findflags(const CCommand& arg) { if (!strcmp(flagPair.second, upperFlag)) { - resolvedFlag = flagPair.first; + resolvedFlag |= flagPair.first; break; } } diff --git a/NorthstarDLL/printmaps.cpp b/NorthstarDLL/printmaps.cpp index 4aa28f3e..7a12b1fe 100644 --- a/NorthstarDLL/printmaps.cpp +++ b/NorthstarDLL/printmaps.cpp @@ -98,7 +98,7 @@ void RefreshMapList() } // get maps in game dir - for (fs::directory_entry file : fs::directory_iterator(fmt::format("{}/maps", "r2"))) + for (fs::directory_entry file : fs::directory_iterator(fmt::format("{}/maps", R2::g_pModName))) { if (file.path().extension() == ".bsp") { diff --git a/NorthstarDLL/r2engine.cpp b/NorthstarDLL/r2engine.cpp index a3b6225f..5a5568c1 100644 --- a/NorthstarDLL/r2engine.cpp +++ b/NorthstarDLL/r2engine.cpp @@ -16,6 +16,8 @@ namespace R2 CBaseClient* g_pClientArray; server_state_t* g_pServerState; + + char* g_pModName = nullptr; // we cant set this up here atm since we dont have an offset to it in engine, instead we store it in IsRespawnMod } // namespace R2 ON_DLL_LOAD("engine.dll", R2Engine, (CModule module)) diff --git a/NorthstarDLL/r2engine.h b/NorthstarDLL/r2engine.h index 717c1799..e5755c54 100644 --- a/NorthstarDLL/r2engine.h +++ b/NorthstarDLL/r2engine.h @@ -194,4 +194,6 @@ namespace R2 }; extern server_state_t* g_pServerState; + + extern char* g_pModName; } // namespace R2 diff --git a/NorthstarDLL/rpakfilesystem.cpp b/NorthstarDLL/rpakfilesystem.cpp index 7ab1b723..46e0e725 100644 --- a/NorthstarDLL/rpakfilesystem.cpp +++ b/NorthstarDLL/rpakfilesystem.cpp @@ -2,6 +2,7 @@ #include "rpakfilesystem.h" #include "modmanager.h" #include "dedicated.h" +#include "tier0.h" AUTOHOOK_INIT() @@ -14,7 +15,7 @@ struct PakLoadFuncs void* unk1[2]; void* (*UnloadPak)(int iPakHandle, void* callback); void* unk2[17]; - void* (*ReadFullFileFromDisk)(const char* pPath, void* a2); + void* (*ReadFileAsync)(const char* pPath, void* a2); }; PakLoadFuncs* g_pakLoadApi; @@ -136,7 +137,7 @@ int,, (char* pPath, void* unknownSingleton, int flags, void* callback0, void* ca // do this after custom paks load and in bShouldLoadPaks so we only ever call this on the root pakload call // todo: could probably add some way to flag custom paks to not be loaded on dedicated servers in rpak.json - if (IsDedicatedServer() && strncmp(&originalPath[0], "common", 6)) // dedicated only needs common and common_mp + if (IsDedicatedServer() && (Tier0::CommandLine()->CheckParm("-nopakdedi") || strncmp(&originalPath[0], "common", 6))) // dedicated only needs common and common_mp { spdlog::info("Not loading pak {} for dedicated server", originalPath); return -1; @@ -170,7 +171,7 @@ void*,, (int iPakHandle, void* callback)) // we hook this exclusively for resolving stbsp paths, but seemingly it's also used for other stuff like vpk and rpak loads // possibly just async loading altogether? -HOOK(ReadFullFileFromDiskHook, ReadFullFileFromDisk, +HOOK(ReadFileAsyncHook, ReadFileAsync, void*, , (const char* pPath, void* a2)) { fs::path path(pPath); @@ -182,7 +183,6 @@ void*, , (const char* pPath, void* a2)) spdlog::info("LoadStreamBsp: {}", filename.string()); // resolve modded stbsp path so we can load mod stbsps - auto modFile = g_pModManager->m_ModFiles.find(g_pModManager->NormaliseModFilePath(fs::path("maps" / filename))); if (modFile != g_pModManager->m_ModFiles.end()) { @@ -194,7 +194,9 @@ void*, , (const char* pPath, void* a2)) } } - void* ret = ReadFullFileFromDisk(pPath, a2); + // this is used for reading vpk, rpak, starpak, stbsp, and mprj also + + void* ret = ReadFileAsync(pPath, a2); if (allocatedNewPath) delete[] allocatedNewPath; @@ -213,5 +215,5 @@ ON_DLL_LOAD("engine.dll", RpakFilesystem, (CModule module)) LoadPakAsyncHook.Dispatch(g_pakLoadApi->LoadPakAsync); UnloadPakHook.Dispatch(g_pakLoadApi->UnloadPak); - ReadFullFileFromDiskHook.Dispatch(g_pakLoadApi->ReadFullFileFromDisk); + ReadFileAsyncHook.Dispatch(g_pakLoadApi->ReadFileAsync); } diff --git a/NorthstarDLL/scriptserverbrowser.cpp b/NorthstarDLL/scriptserverbrowser.cpp index bdc49303..0e647f45 100644 --- a/NorthstarDLL/scriptserverbrowser.cpp +++ b/NorthstarDLL/scriptserverbrowser.cpp @@ -409,6 +409,13 @@ SQRESULT SQ_CompleteAuthWithLocalServer(void* sqvm) return SQRESULT_NULL; } +// string function NSGetAuthFailReason() +SQRESULT SQ_GetAuthFailReason(void* sqvm) +{ + g_pSquirrel->pushstring(sqvm, g_pMasterServerManager->m_sAuthFailureReason.c_str(), -1); + return SQRESULT_NOTNULL; +} + ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ScriptServerBrowser, ClientSquirrel, (CModule module)) { g_pSquirrel->AddFuncRegistration("bool", "NSIsMasterServerAuthenticated", "", "", SQ_IsMasterServerAuthenticated); @@ -440,4 +447,6 @@ ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ScriptServerBrowser, ClientSquirrel, ( g_pSquirrel->AddFuncRegistration("void", "NSTryAuthWithLocalServer", "", "", SQ_TryAuthWithLocalServer); g_pSquirrel->AddFuncRegistration("void", "NSCompleteAuthWithLocalServer", "", "", SQ_CompleteAuthWithLocalServer); + + g_pSquirrel->AddFuncRegistration("string", "NSGetAuthFailReason", "", "", SQ_GetAuthFailReason); } diff --git a/NorthstarDLL/serverpresence.cpp b/NorthstarDLL/serverpresence.cpp index 4e9c5c28..cfc1c213 100644 --- a/NorthstarDLL/serverpresence.cpp +++ b/NorthstarDLL/serverpresence.cpp @@ -117,6 +117,7 @@ void ServerPresenceManager::CreatePresence() m_ServerPresence.m_bIsSingleplayerServer = false; m_bHasPresence = true; + m_bFirstPresenceUpdate = true; // code that's calling this should set up the reset fields at this point } @@ -142,6 +143,16 @@ void ServerPresenceManager::RunFrame(double flCurrentTime) if ((flCurrentTime - m_flLastPresenceUpdate) * 1000 < Cvar_ns_server_presence_update_rate->GetFloat()) return; + // is this the first frame we're updating this presence? + if (m_bFirstPresenceUpdate) + { + // let reporters setup/clear any state + for (ServerPresenceReporter* reporter : m_vPresenceReporters) + reporter->CreatePresence(&m_ServerPresence); + + m_bFirstPresenceUpdate = false; + } + m_flLastPresenceUpdate = flCurrentTime; for (ServerPresenceReporter* reporter : m_vPresenceReporters) @@ -178,7 +189,7 @@ void ServerPresenceManager::SetPassword(const char* pPassword) strncpy_s(m_ServerPresence.m_Password, sizeof(m_ServerPresence.m_Password), pPassword, sizeof(m_ServerPresence.m_Password) - 1); } -void ServerPresenceManager::SetMap(const char* pMapName, bool isInitialising = false) +void ServerPresenceManager::SetMap(const char* pMapName, bool isInitialising) { // if the server is initialising (i.e. this is first map) on sp, set the server to sp if (isInitialising) diff --git a/NorthstarDLL/serverpresence.h b/NorthstarDLL/serverpresence.h index 018cd862..f27c9393 100644 --- a/NorthstarDLL/serverpresence.h +++ b/NorthstarDLL/serverpresence.h @@ -42,6 +42,7 @@ struct ServerPresence class ServerPresenceReporter { public: + virtual void CreatePresence(const ServerPresence* pServerPresence) {} virtual void ReportPresence(const ServerPresence* pServerPresence) {} virtual void DestroyPresence(const ServerPresence* pServerPresence) {} }; @@ -52,6 +53,7 @@ class ServerPresenceManager ServerPresence m_ServerPresence; bool m_bHasPresence = false; + bool m_bFirstPresenceUpdate = false; std::vector m_vPresenceReporters; diff --git a/NorthstarDLL/squirrel.cpp b/NorthstarDLL/squirrel.cpp index e5f29ee6..bede510e 100644 --- a/NorthstarDLL/squirrel.cpp +++ b/NorthstarDLL/squirrel.cpp @@ -25,7 +25,7 @@ template void* (*sq_compiler_create)(void* sqvm, void* a template void* sq_compiler_createHook(void* sqvm, void* a2, void* a3, SQBool bShouldThrowError) { // store whether errors generated from this compile should be fatal - if (sqvm == g_pSquirrel->sqvm2) + if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel->sqvm2) g_pSquirrel->m_bCompilationErrorsFatal = bShouldThrowError; else g_pSquirrel->m_bCompilationErrorsFatal = bShouldThrowError; @@ -71,7 +71,7 @@ template void (*DestroyVM)(void* a1, void* sqvm); template void DestroyVMHook(void* a1, void* sqvm) { ScriptContext realContext = context; // ui and client use the same function so we use this for prints - if (sqvm == g_pSquirrel->sqvm) + if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel->sqvm) { realContext = ScriptContext::UI; g_pSquirrel->VMDestroyed(); @@ -87,7 +87,7 @@ template void ScriptCompileErrorHook(void* sqvm, const c { bool bIsFatalError = g_pSquirrel->m_bCompilationErrorsFatal; ScriptContext realContext = context; // ui and client use the same function so we use this for prints - if (sqvm == g_pSquirrel->sqvm2) + if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel->sqvm2) { realContext = ScriptContext::UI; bIsFatalError = g_pSquirrel->m_bCompilationErrorsFatal; -- cgit v1.2.3