From 4bf3def2ac5719fdba37bd0f0d3383f67abe6516 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 26 Dec 2021 02:29:27 +0000 Subject: add setplaylistvaroverride command for setting overrides on dedi from commandline --- NorthstarDedicatedTest/playlist.cpp | 23 +++++++++++++++++++++++ NorthstarDedicatedTest/serverauthentication.cpp | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp index b853a40a..ef399347 100644 --- a/NorthstarDedicatedTest/playlist.cpp +++ b/NorthstarDedicatedTest/playlist.cpp @@ -5,6 +5,7 @@ #include "gameutils.h" #include "hookutils.h" #include "dedicated.h" +#include "squirrel.h" typedef char(*Onclc_SetPlaylistVarOverrideType)(void* a1, void* a2); Onclc_SetPlaylistVarOverrideType Onclc_SetPlaylistVarOverride; @@ -21,6 +22,14 @@ void SetPlaylistCommand(const CCommand& args) SetCurrentPlaylist(args.Arg(1)); } +void SetPlaylistVarOverrideCommand(const CCommand& args) +{ + if (args.ArgC() < 3) + return; + + SetPlaylistVarOverride(args.Arg(1), args.Arg(2)); +} + char Onclc_SetPlaylistVarOverrideHook(void* a1, void* a2) { // the private_match playlist is the only situation where there should be any legitimate sending of this netmessage @@ -42,6 +51,7 @@ void SetPlaylistVarOverrideHook(const char* varName, const char* value) void InitialisePlaylistHooks(HMODULE baseAddress) { RegisterConCommand("setplaylist", SetPlaylistCommand, "Sets the current playlist", FCVAR_NONE); + RegisterConCommand("setplaylistvaroverride", SetPlaylistVarOverrideCommand, "sets a playlist var override", FCVAR_NONE); // note: clc_SetPlaylistVarOverride is pretty insecure, since it allows for entirely arbitrary playlist var overrides to be sent to the server // this is somewhat restricted on custom servers to prevent it being done outside of private matches, but ideally it should be disabled altogether, since the custom menus won't use it anyway // this should only really be accepted if you want vanilla client compatibility @@ -58,4 +68,17 @@ void InitialisePlaylistHooks(HMODULE baseAddress) TempReadWrite rw(ptr); *((char*)ptr) = 0xC3; // jmp => ret } + + if (IsDedicated()) + { + // patch to allow setplaylistvaroverride to be called before map init on dedicated + void* ptr = (char*)baseAddress + 0x18ED17; + TempReadWrite rw(ptr); + *((char*)ptr) = (char)0x90; + *((char*)ptr + 1) = (char)0x90; + *((char*)ptr + 2) = (char)0x90; + *((char*)ptr + 3) = (char)0x90; + *((char*)ptr + 4) = (char)0x90; + *((char*)ptr + 5) = (char)0x90; + } } \ No newline at end of file diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp index 21be404c..5351dfdc 100644 --- a/NorthstarDedicatedTest/serverauthentication.cpp +++ b/NorthstarDedicatedTest/serverauthentication.cpp @@ -437,7 +437,7 @@ void InitialiseServerAuthentication(HMODULE baseAddress) Cvar_net_chan_limit_mode = RegisterConVar("net_chan_limit_mode", "0", FCVAR_GAMEDLL, "The mode for netchan processing limits: 0 = none, 1 = kick, 2 = log"); Cvar_net_chan_limit_msec_per_sec = RegisterConVar("net_chan_limit_msec_per_sec", "0", FCVAR_GAMEDLL, "Netchannel processing is limited to so many milliseconds, abort connection if exceeding budget"); Cvar_ns_player_auth_port = RegisterConVar("ns_player_auth_port", "8081", FCVAR_GAMEDLL, ""); - Cvar_sv_querylimit_per_sec = RegisterConVar("sv_querylimit_per_sec", "10", FCVAR_GAMEDLL, ""); + Cvar_sv_querylimit_per_sec = RegisterConVar("sv_querylimit_per_sec", "15", FCVAR_GAMEDLL, ""); HookEnabler hook; ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x114430, &CBaseServer__ConnectClientHook, reinterpret_cast(&CBaseServer__ConnectClient)); -- cgit v1.2.3 From 3296aeae3cc035cfc20b9c7da40f7c5690e92daa Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 26 Dec 2021 03:29:57 +0000 Subject: better httplib errors and higher timeouts --- NorthstarDedicatedTest/masterserver.cpp | 69 +++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index fa918c5c..a630fc6e 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -35,6 +35,39 @@ CHostState__State_ChangeLevelSPType CHostState__State_ChangeLevelSP; typedef void(*CHostState__State_GameShutdownType)(CHostState* hostState); CHostState__State_GameShutdownType CHostState__State_GameShutdown; +const char* HttplibErrorToString(httplib::Error error) +{ + switch (error) + { + case httplib::Error::Success: + return "httplib::Error::Success"; + case httplib::Error::Unknown: + return "httplib::Error::Unknown"; + case httplib::Error::Connection: + return "httplib::Error::Connection"; + case httplib::Error::BindIPAddress: + return "httplib::Error::BindIPAddress"; + case httplib::Error::Read: + return "httplib::Error::Read"; + case httplib::Error::Write: + return "httplib::Error::Write"; + case httplib::Error::ExceedRedirectCount: + return "httplib::Error::ExceedRedirectCount"; + case httplib::Error::Canceled: + return "httplib::Error::Canceled"; + case httplib::Error::SSLConnection: + return "httplib::Error::SSLConnection"; + case httplib::Error::SSLLoadingCerts: + return "httplib::Error::SSLLoadingCerts"; + case httplib::Error::SSLServerVerification: + return "httplib::Error::SSLServerVerification"; + case httplib::Error::UnsupportedMultipartBoundaryChars: + return "httplib::Error::UnsupportedMultipartBoundaryChars"; + } + + return ""; +} + RemoteServerInfo::RemoteServerInfo(const char* newId, const char* newName, const char* newDescription, const char* newMap, const char* newPlaylist, int newPlayerCount, int newMaxPlayers, bool newRequiresPassword) { // passworded servers don't have public ips @@ -80,6 +113,8 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); spdlog::info("Trying to authenticate with northstar masterserver for user {}", uidStr); @@ -113,7 +148,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or } else { - spdlog::error("Failed performing northstar origin auth: error {}", result.error()); + spdlog::error("Failed performing northstar origin auth: error {}", HttplibErrorToString(result.error())); m_successfullyConnected = false; } @@ -143,6 +178,8 @@ void MasterServerManager::RequestServerList() httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); spdlog::info("Requesting server list from {}", Cvar_ns_masterserver_hostname->m_pszString); @@ -248,7 +285,7 @@ void MasterServerManager::RequestServerList() } else { - spdlog::error("Failed requesting servers: error {}", result.error()); + spdlog::error("Failed requesting servers: error {}", HttplibErrorToString(result.error())); m_successfullyConnected = false; } @@ -272,6 +309,8 @@ void MasterServerManager::RequestMainMenuPromos() httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); if (auto result = http.Get("/client/mainmenupromos")) { @@ -345,7 +384,7 @@ void MasterServerManager::RequestMainMenuPromos() } else { - spdlog::error("Failed requesting main menu promos: error {}", result.error()); + spdlog::error("Failed requesting main menu promos: error {}", HttplibErrorToString(result.error())); m_successfullyConnected = false; } @@ -371,6 +410,8 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); if (auto result = http.Post(fmt::format("/client/auth_with_self?id={}&playerToken={}", uid, playerToken).c_str())) { @@ -440,7 +481,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken } else { - spdlog::error("Failed authenticating with own server: error {}", result.error()); + spdlog::error("Failed authenticating with own server: error {}", HttplibErrorToString(result.error())); m_successfullyConnected = false; m_successfullyAuthenticatedWithGameServer = false; m_scriptAuthenticatingWithGameServer = false; @@ -479,6 +520,8 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); spdlog::info("Attempting authentication with server of id \"{}\"", serverId); @@ -531,7 +574,7 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c } else { - spdlog::error("Failed authenticating with server: error {}", result.error()); + spdlog::error("Failed authenticating with server: error {}", HttplibErrorToString(result.error())); m_successfullyConnected = false; m_successfullyAuthenticatedWithGameServer = false; m_scriptAuthenticatingWithGameServer = false; @@ -561,6 +604,8 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name std::thread requestThread([this, port, authPort, name, description, map, playlist, maxPlayers, password] { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); m_ownServerId[0] = 0; @@ -647,6 +692,8 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name std::thread heartbeatThread([this] { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); while (*m_ownServerId) { @@ -659,7 +706,7 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name } else { - spdlog::error("Failed authenticating with server: error {}", result.error()); + spdlog::error("Failed authenticating with server: error {}", HttplibErrorToString(result.error())); m_successfullyConnected = false; } }); @@ -676,6 +723,8 @@ void MasterServerManager::UpdateServerMapAndPlaylist(char* map, char* playlist, std::thread requestThread([this, map, playlist, maxPlayers] { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); // we dont process this at all atm, maybe do later, but atm not necessary if (auto result = http.Post(fmt::format("/server/update_values?id={}&map={}&playlist={}&maxPlayers={}", m_ownServerId, map, playlist, maxPlayers).c_str())) @@ -700,6 +749,8 @@ void MasterServerManager::UpdateServerPlayerCount(int playerCount) std::thread requestThread([this, playerCount] { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); // we dont process this at all atm, maybe do later, but atm not necessary if (auto result = http.Post(fmt::format("/server/update_values?id={}&playerCount={}", m_ownServerId, playerCount).c_str())) @@ -728,7 +779,9 @@ void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata, std::string playerIdTemp(playerId); std::thread requestThread([this, playerIdTemp, pdata, pdataSize] { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); - http.set_connection_timeout(25); + http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); httplib::MultipartFormDataItems requestItems = { { "pdata", std::string(pdata, pdataSize), "file.pdata", "application/octet-stream"} @@ -759,6 +812,8 @@ void MasterServerManager::RemoveSelfFromServerList() std::thread requestThread([this] { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); // we dont process this at all atm, maybe do later, but atm not necessary if (auto result = http.Delete(fmt::format("/server/remove_server?id={}", m_ownServerId).c_str())) -- cgit v1.2.3 From ce6127ae96022ce6e803a876a2e39eed7bd754ea Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 26 Dec 2021 05:22:33 +0000 Subject: fix potentially unsafe concommand --- NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj | 2 ++ .../NorthstarDedicatedTest.vcxproj.filters | 6 ++++++ NorthstarDedicatedTest/dllmain.cpp | 2 ++ NorthstarDedicatedTest/miscserverfixes.cpp | 13 +++++++++++++ NorthstarDedicatedTest/miscserverfixes.h | 1 + 5 files changed, 24 insertions(+) create mode 100644 NorthstarDedicatedTest/miscserverfixes.cpp create mode 100644 NorthstarDedicatedTest/miscserverfixes.h diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index c684b69d..29dea6dc 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -579,6 +579,7 @@ + @@ -614,6 +615,7 @@ + diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 7c856ea1..306ac763 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -1386,6 +1386,9 @@ Header Files\include\openssl\internal + + Header Files\Server + @@ -1493,6 +1496,9 @@ Source Files\Client + + Source Files\Server + diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 212b5711..78edb297 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -24,6 +24,7 @@ #include "scriptbrowserhooks.h" #include "scriptmainmenupromos.h" #include "miscclientfixes.h" +#include "miscserverfixes.h" #include "memalloc.h" bool initialised = false; @@ -110,6 +111,7 @@ void InitialiseNorthstar() AddDllLoadCallback("engine.dll", InitialiseServerAuthentication); AddDllLoadCallback("engine.dll", InitialiseSharedMasterServer); AddDllLoadCallback("server.dll", InitialiseMiscServerScriptCommand); + AddDllLoadCallback("server.dll", InitialiseMiscServerFixes); AddDllLoadCallback("engine.dll", InitialisePlaylistHooks); diff --git a/NorthstarDedicatedTest/miscserverfixes.cpp b/NorthstarDedicatedTest/miscserverfixes.cpp new file mode 100644 index 00000000..2007a30c --- /dev/null +++ b/NorthstarDedicatedTest/miscserverfixes.cpp @@ -0,0 +1,13 @@ +#include "pch.h" +#include "miscserverfixes.h" +#include "hookutils.h" + +void InitialiseMiscServerFixes(HMODULE baseAddress) +{ + // ret at the start of the concommand GenerateObjFile as it can crash servers + { + void* ptr = (char*)baseAddress + 0x38D920; + TempReadWrite rw(ptr); + *((char*)ptr) = (char)0xC3; + } +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/miscserverfixes.h b/NorthstarDedicatedTest/miscserverfixes.h new file mode 100644 index 00000000..d1c05a6b --- /dev/null +++ b/NorthstarDedicatedTest/miscserverfixes.h @@ -0,0 +1 @@ +void InitialiseMiscServerFixes(HMODULE baseAddress); \ No newline at end of file -- cgit v1.2.3 From 2bb9e5b29ab08062614b2d52c430f9097bf2106f Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 26 Dec 2021 17:50:29 +0000 Subject: add more descriptive message for AddSelfToServerList failure --- NorthstarDedicatedTest/masterserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index a630fc6e..706f60ec 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -706,7 +706,7 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name } else { - spdlog::error("Failed authenticating with server: error {}", HttplibErrorToString(result.error())); + spdlog::error("Failed adding self to server list: error {}", HttplibErrorToString(result.error())); m_successfullyConnected = false; } }); -- cgit v1.2.3 From 609f480d2b87ca2fbc91240cc6b5c52a4addfde6 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 26 Dec 2021 19:54:56 +0000 Subject: add better native crash logging and minidump creation --- .../NorthstarDedicatedTest.vcxproj | 4 +- NorthstarDedicatedTest/logging.cpp | 156 +++++++++++++++++++++ 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index 29dea6dc..0fd30949 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -136,7 +136,7 @@ Windows true false - $(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcrypto_static.lib;$(ProjectDir)include\libssl_static.lib;%(AdditionalDependencies) + $(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcrypto_static.lib;$(ProjectDir)include\libssl_static.lib;dbghelp.lib;%(AdditionalDependencies) @@ -164,7 +164,7 @@ true true false - $(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcrypto_static.lib;$(ProjectDir)include\libssl_static.lib;%(AdditionalDependencies) + $(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcrypto_static.lib;$(ProjectDir)include\libssl_static.lib;dbghelp.lib;%(AdditionalDependencies) diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp index 55627fb2..5fa7e39d 100644 --- a/NorthstarDedicatedTest/logging.cpp +++ b/NorthstarDedicatedTest/logging.cpp @@ -4,11 +4,167 @@ #include "spdlog/sinks/basic_file_sink.h" #include "hookutils.h" #include "gameutils.h" +#include "dedicated.h" #include #include +#include +#include + +long __stdcall ExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) +{ + static bool logged = false; + if (logged) + return EXCEPTION_CONTINUE_SEARCH; + + const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode; + if (exceptionCode != EXCEPTION_ACCESS_VIOLATION && exceptionCode != EXCEPTION_ARRAY_BOUNDS_EXCEEDED && + exceptionCode != EXCEPTION_DATATYPE_MISALIGNMENT && exceptionCode != EXCEPTION_FLT_DENORMAL_OPERAND && + exceptionCode != EXCEPTION_FLT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_FLT_INEXACT_RESULT && + exceptionCode != EXCEPTION_FLT_INVALID_OPERATION && exceptionCode != EXCEPTION_FLT_OVERFLOW && + exceptionCode != EXCEPTION_FLT_STACK_CHECK && exceptionCode != EXCEPTION_FLT_UNDERFLOW && + exceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION && exceptionCode != EXCEPTION_IN_PAGE_ERROR && + exceptionCode != EXCEPTION_INT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_INT_OVERFLOW && + exceptionCode != EXCEPTION_INVALID_DISPOSITION && exceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION && + exceptionCode != EXCEPTION_PRIV_INSTRUCTION && exceptionCode != EXCEPTION_STACK_OVERFLOW) + return EXCEPTION_CONTINUE_SEARCH; + + std::stringstream exceptionCause; + switch (exceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_IN_PAGE_ERROR: + { + exceptionCause << "Cause: Access Violation" << std::endl; + + auto exceptionInfo0 = exceptionInfo->ExceptionRecord->ExceptionInformation[0]; + auto exceptionInfo1 = exceptionInfo->ExceptionRecord->ExceptionInformation[1]; + + if (!exceptionInfo0) + exceptionCause << "Attempted to read from: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + else if (exceptionInfo0 == 1) + exceptionCause << "Attempted to write to: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + else if (exceptionInfo0 == 8) + exceptionCause << "Data Execution Prevention (DEP) at: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + else + exceptionCause << "Unknown access violation at: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + + break; + } + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + exceptionCause << "Cause: Array bounds exceeded"; + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + exceptionCause << "Cause: Datatype misalignment"; + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + exceptionCause << "Cause: Denormal operand"; + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + exceptionCause << "Cause: Divide by zero"; + break; + case EXCEPTION_FLT_INEXACT_RESULT: + exceptionCause << "Cause: Inexact result"; + break; + case EXCEPTION_FLT_INVALID_OPERATION: + exceptionCause << "Cause: invalid operation"; + break; + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_INT_OVERFLOW: + exceptionCause << "Cause: Numeric overflow"; + break; + case EXCEPTION_FLT_UNDERFLOW: + exceptionCause << "Cause: Numeric underflow"; + break; + case EXCEPTION_FLT_STACK_CHECK: + exceptionCause << "Cause: Stack check"; + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + exceptionCause << "Cause: Illegal instruction"; + break; + case EXCEPTION_INVALID_DISPOSITION: + exceptionCause << "Cause: Invalid disposition"; + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + exceptionCause << "Cause: Noncontinuable exception"; + break; + case EXCEPTION_PRIV_INSTRUCTION: + exceptionCause << "Cause: Priv instruction"; + break; + case EXCEPTION_STACK_OVERFLOW: + exceptionCause << "Cause: Stack overflow"; + break; + default: + exceptionCause << "Cause: Unknown"; + break; + } + + void* exceptionAddress = exceptionInfo->ExceptionRecord->ExceptionAddress; + + HMODULE crashedModuleHandle; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(exceptionAddress), &crashedModuleHandle); + + MODULEINFO crashedModuleInfo; + GetModuleInformation(GetCurrentProcess(), crashedModuleHandle, &crashedModuleInfo, sizeof(crashedModuleInfo)); + + char crashedModuleFullName[MAX_PATH]; + GetModuleFileNameExA(GetCurrentProcess(), crashedModuleHandle, crashedModuleFullName, MAX_PATH); + char* crashedModuleName = strrchr(crashedModuleFullName, '\\') + 1; + + DWORD crashedModuleOffset = ((DWORD)exceptionAddress) - ((DWORD)crashedModuleInfo.lpBaseOfDll); + CONTEXT* exceptionContext = exceptionInfo->ContextRecord; + + spdlog::error("Northstar has crashed! a minidump has been written and exception info is available below:"); + spdlog::error(exceptionCause.str()); + spdlog::error("Address: {} + 0x{0:x}", crashedModuleName, crashedModuleOffset); + spdlog::error("RAX: 0x{0:x}", exceptionContext->Rax); + spdlog::error("RBX: 0x{0:x}", exceptionContext->Rbx); + spdlog::error("RCX: 0x{0:x}", exceptionContext->Rcx); + spdlog::error("RDX: 0x{0:x}", exceptionContext->Rdx); + spdlog::error("RSI: 0x{0:x}", exceptionContext->Rsi); + spdlog::error("RDI: 0x{0:x}", exceptionContext->Rdi); + spdlog::error("RBP: 0x{0:x}", exceptionContext->Rbp); + spdlog::error("RSP: 0x{0:x}", exceptionContext->Rsp); + spdlog::error("R8: 0x{0:x}", exceptionContext->R8); + spdlog::error("R9: 0x{0:x}", exceptionContext->R9); + spdlog::error("R10: 0x{0:x}", exceptionContext->R10); + spdlog::error("R11: 0x{0:x}", exceptionContext->R11); + spdlog::error("R12: 0x{0:x}", exceptionContext->R12); + spdlog::error("R13: 0x{0:x}", exceptionContext->R13); + spdlog::error("R14: 0x{0:x}", exceptionContext->R14); + spdlog::error("R15: 0x{0:x}", exceptionContext->R15); + + time_t time = std::time(nullptr); + tm currentTime = *std::localtime(&time); + std::stringstream stream; + stream << std::put_time(¤tTime, "R2Northstar/logs/nsdump%d-%m-%Y %H-%M-%S.dmp"); + + auto hMinidumpFile = CreateFileA(stream.str().c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (hMinidumpFile) + { + MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo; + dumpExceptionInfo.ThreadId = GetCurrentThreadId(); + dumpExceptionInfo.ExceptionPointers = exceptionInfo; + dumpExceptionInfo.ClientPointers = false; + + MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hMinidumpFile, MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory), &dumpExceptionInfo, nullptr, nullptr); + CloseHandle(hMinidumpFile); + } + else + spdlog::error("Failed to write minidump file {}!", stream.str()); + + if (!IsDedicated()) + MessageBoxA(0, "Northstar has crashed! A crash log and dump can be found in R2Northstar/logs", "Northstar has crashed!", MB_ICONERROR | MB_OK); + + logged = true; + return EXCEPTION_EXECUTE_HANDLER; +} + void InitialiseLogging() { + AddVectoredExceptionHandler(TRUE, ExceptionFilter); + AllocConsole(); freopen("CONOUT$", "w", stdout); -- cgit v1.2.3 From d00f63fe45dc653b04e15a0448a5f5ed7c178328 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 26 Dec 2021 20:44:38 +0000 Subject: ensure exception logging doesn't happen when a debugger is attached --- NorthstarDedicatedTest/logging.cpp | 264 +++++++++++++++++++------------------ 1 file changed, 134 insertions(+), 130 deletions(-) diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp index 5fa7e39d..09ae6961 100644 --- a/NorthstarDedicatedTest/logging.cpp +++ b/NorthstarDedicatedTest/logging.cpp @@ -16,145 +16,149 @@ long __stdcall ExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) if (logged) return EXCEPTION_CONTINUE_SEARCH; - const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode; - if (exceptionCode != EXCEPTION_ACCESS_VIOLATION && exceptionCode != EXCEPTION_ARRAY_BOUNDS_EXCEEDED && - exceptionCode != EXCEPTION_DATATYPE_MISALIGNMENT && exceptionCode != EXCEPTION_FLT_DENORMAL_OPERAND && - exceptionCode != EXCEPTION_FLT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_FLT_INEXACT_RESULT && - exceptionCode != EXCEPTION_FLT_INVALID_OPERATION && exceptionCode != EXCEPTION_FLT_OVERFLOW && - exceptionCode != EXCEPTION_FLT_STACK_CHECK && exceptionCode != EXCEPTION_FLT_UNDERFLOW && - exceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION && exceptionCode != EXCEPTION_IN_PAGE_ERROR && - exceptionCode != EXCEPTION_INT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_INT_OVERFLOW && - exceptionCode != EXCEPTION_INVALID_DISPOSITION && exceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION && - exceptionCode != EXCEPTION_PRIV_INSTRUCTION && exceptionCode != EXCEPTION_STACK_OVERFLOW) - return EXCEPTION_CONTINUE_SEARCH; - - std::stringstream exceptionCause; - switch (exceptionCode) - { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_IN_PAGE_ERROR: + if (!IsDebuggerPresent()) { - exceptionCause << "Cause: Access Violation" << std::endl; + const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode; + if (exceptionCode != EXCEPTION_ACCESS_VIOLATION && exceptionCode != EXCEPTION_ARRAY_BOUNDS_EXCEEDED && + exceptionCode != EXCEPTION_DATATYPE_MISALIGNMENT && exceptionCode != EXCEPTION_FLT_DENORMAL_OPERAND && + exceptionCode != EXCEPTION_FLT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_FLT_INEXACT_RESULT && + exceptionCode != EXCEPTION_FLT_INVALID_OPERATION && exceptionCode != EXCEPTION_FLT_OVERFLOW && + exceptionCode != EXCEPTION_FLT_STACK_CHECK && exceptionCode != EXCEPTION_FLT_UNDERFLOW && + exceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION && exceptionCode != EXCEPTION_IN_PAGE_ERROR && + exceptionCode != EXCEPTION_INT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_INT_OVERFLOW && + exceptionCode != EXCEPTION_INVALID_DISPOSITION && exceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION && + exceptionCode != EXCEPTION_PRIV_INSTRUCTION && exceptionCode != EXCEPTION_STACK_OVERFLOW) + return EXCEPTION_CONTINUE_SEARCH; + + std::stringstream exceptionCause; + switch (exceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_IN_PAGE_ERROR: + { + exceptionCause << "Cause: Access Violation" << std::endl; - auto exceptionInfo0 = exceptionInfo->ExceptionRecord->ExceptionInformation[0]; - auto exceptionInfo1 = exceptionInfo->ExceptionRecord->ExceptionInformation[1]; + auto exceptionInfo0 = exceptionInfo->ExceptionRecord->ExceptionInformation[0]; + auto exceptionInfo1 = exceptionInfo->ExceptionRecord->ExceptionInformation[1]; - if (!exceptionInfo0) - exceptionCause << "Attempted to read from: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; - else if (exceptionInfo0 == 1) - exceptionCause << "Attempted to write to: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; - else if (exceptionInfo0 == 8) - exceptionCause << "Data Execution Prevention (DEP) at: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; - else - exceptionCause << "Unknown access violation at: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + if (!exceptionInfo0) + exceptionCause << "Attempted to read from: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + else if (exceptionInfo0 == 1) + exceptionCause << "Attempted to write to: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + else if (exceptionInfo0 == 8) + exceptionCause << "Data Execution Prevention (DEP) at: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; + else + exceptionCause << "Unknown access violation at: 0x" << std::setw(8) << std::setfill('0') << std::hex << exceptionInfo1; - break; - } - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - exceptionCause << "Cause: Array bounds exceeded"; - break; - case EXCEPTION_DATATYPE_MISALIGNMENT: - exceptionCause << "Cause: Datatype misalignment"; - break; - case EXCEPTION_FLT_DENORMAL_OPERAND: - exceptionCause << "Cause: Denormal operand"; - break; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - exceptionCause << "Cause: Divide by zero"; - break; - case EXCEPTION_FLT_INEXACT_RESULT: - exceptionCause << "Cause: Inexact result"; - break; - case EXCEPTION_FLT_INVALID_OPERATION: - exceptionCause << "Cause: invalid operation"; - break; - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_INT_OVERFLOW: - exceptionCause << "Cause: Numeric overflow"; - break; - case EXCEPTION_FLT_UNDERFLOW: - exceptionCause << "Cause: Numeric underflow"; - break; - case EXCEPTION_FLT_STACK_CHECK: - exceptionCause << "Cause: Stack check"; - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - exceptionCause << "Cause: Illegal instruction"; - break; - case EXCEPTION_INVALID_DISPOSITION: - exceptionCause << "Cause: Invalid disposition"; - break; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - exceptionCause << "Cause: Noncontinuable exception"; - break; - case EXCEPTION_PRIV_INSTRUCTION: - exceptionCause << "Cause: Priv instruction"; - break; - case EXCEPTION_STACK_OVERFLOW: - exceptionCause << "Cause: Stack overflow"; - break; - default: - exceptionCause << "Cause: Unknown"; - break; - } + break; + } + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + exceptionCause << "Cause: Array bounds exceeded"; + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + exceptionCause << "Cause: Datatype misalignment"; + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + exceptionCause << "Cause: Denormal operand"; + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + exceptionCause << "Cause: Divide by zero"; + break; + case EXCEPTION_FLT_INEXACT_RESULT: + exceptionCause << "Cause: Inexact result"; + break; + case EXCEPTION_FLT_INVALID_OPERATION: + exceptionCause << "Cause: invalid operation"; + break; + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_INT_OVERFLOW: + exceptionCause << "Cause: Numeric overflow"; + break; + case EXCEPTION_FLT_UNDERFLOW: + exceptionCause << "Cause: Numeric underflow"; + break; + case EXCEPTION_FLT_STACK_CHECK: + exceptionCause << "Cause: Stack check"; + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + exceptionCause << "Cause: Illegal instruction"; + break; + case EXCEPTION_INVALID_DISPOSITION: + exceptionCause << "Cause: Invalid disposition"; + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + exceptionCause << "Cause: Noncontinuable exception"; + break; + case EXCEPTION_PRIV_INSTRUCTION: + exceptionCause << "Cause: Priv instruction"; + break; + case EXCEPTION_STACK_OVERFLOW: + exceptionCause << "Cause: Stack overflow"; + break; + default: + exceptionCause << "Cause: Unknown"; + break; + } - void* exceptionAddress = exceptionInfo->ExceptionRecord->ExceptionAddress; - - HMODULE crashedModuleHandle; - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(exceptionAddress), &crashedModuleHandle); - - MODULEINFO crashedModuleInfo; - GetModuleInformation(GetCurrentProcess(), crashedModuleHandle, &crashedModuleInfo, sizeof(crashedModuleInfo)); - - char crashedModuleFullName[MAX_PATH]; - GetModuleFileNameExA(GetCurrentProcess(), crashedModuleHandle, crashedModuleFullName, MAX_PATH); - char* crashedModuleName = strrchr(crashedModuleFullName, '\\') + 1; - - DWORD crashedModuleOffset = ((DWORD)exceptionAddress) - ((DWORD)crashedModuleInfo.lpBaseOfDll); - CONTEXT* exceptionContext = exceptionInfo->ContextRecord; - - spdlog::error("Northstar has crashed! a minidump has been written and exception info is available below:"); - spdlog::error(exceptionCause.str()); - spdlog::error("Address: {} + 0x{0:x}", crashedModuleName, crashedModuleOffset); - spdlog::error("RAX: 0x{0:x}", exceptionContext->Rax); - spdlog::error("RBX: 0x{0:x}", exceptionContext->Rbx); - spdlog::error("RCX: 0x{0:x}", exceptionContext->Rcx); - spdlog::error("RDX: 0x{0:x}", exceptionContext->Rdx); - spdlog::error("RSI: 0x{0:x}", exceptionContext->Rsi); - spdlog::error("RDI: 0x{0:x}", exceptionContext->Rdi); - spdlog::error("RBP: 0x{0:x}", exceptionContext->Rbp); - spdlog::error("RSP: 0x{0:x}", exceptionContext->Rsp); - spdlog::error("R8: 0x{0:x}", exceptionContext->R8); - spdlog::error("R9: 0x{0:x}", exceptionContext->R9); - spdlog::error("R10: 0x{0:x}", exceptionContext->R10); - spdlog::error("R11: 0x{0:x}", exceptionContext->R11); - spdlog::error("R12: 0x{0:x}", exceptionContext->R12); - spdlog::error("R13: 0x{0:x}", exceptionContext->R13); - spdlog::error("R14: 0x{0:x}", exceptionContext->R14); - spdlog::error("R15: 0x{0:x}", exceptionContext->R15); + void* exceptionAddress = exceptionInfo->ExceptionRecord->ExceptionAddress; + + HMODULE crashedModuleHandle; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(exceptionAddress), &crashedModuleHandle); + + MODULEINFO crashedModuleInfo; + GetModuleInformation(GetCurrentProcess(), crashedModuleHandle, &crashedModuleInfo, sizeof(crashedModuleInfo)); + + char crashedModuleFullName[MAX_PATH]; + GetModuleFileNameExA(GetCurrentProcess(), crashedModuleHandle, crashedModuleFullName, MAX_PATH); + char* crashedModuleName = strrchr(crashedModuleFullName, '\\') + 1; + + DWORD crashedModuleOffset = ((DWORD)exceptionAddress) - ((DWORD)crashedModuleInfo.lpBaseOfDll); + CONTEXT* exceptionContext = exceptionInfo->ContextRecord; + + spdlog::error("Northstar has crashed! a minidump has been written and exception info is available below:"); + spdlog::error(exceptionCause.str()); + spdlog::error("Address: {} + 0x{0:x}", crashedModuleName, crashedModuleOffset); + spdlog::error("RAX: 0x{0:x}", exceptionContext->Rax); + spdlog::error("RBX: 0x{0:x}", exceptionContext->Rbx); + spdlog::error("RCX: 0x{0:x}", exceptionContext->Rcx); + spdlog::error("RDX: 0x{0:x}", exceptionContext->Rdx); + spdlog::error("RSI: 0x{0:x}", exceptionContext->Rsi); + spdlog::error("RDI: 0x{0:x}", exceptionContext->Rdi); + spdlog::error("RBP: 0x{0:x}", exceptionContext->Rbp); + spdlog::error("RSP: 0x{0:x}", exceptionContext->Rsp); + spdlog::error("R8: 0x{0:x}", exceptionContext->R8); + spdlog::error("R9: 0x{0:x}", exceptionContext->R9); + spdlog::error("R10: 0x{0:x}", exceptionContext->R10); + spdlog::error("R11: 0x{0:x}", exceptionContext->R11); + spdlog::error("R12: 0x{0:x}", exceptionContext->R12); + spdlog::error("R13: 0x{0:x}", exceptionContext->R13); + spdlog::error("R14: 0x{0:x}", exceptionContext->R14); + spdlog::error("R15: 0x{0:x}", exceptionContext->R15); + + time_t time = std::time(nullptr); + tm currentTime = *std::localtime(&time); + std::stringstream stream; + stream << std::put_time(¤tTime, "R2Northstar/logs/nsdump%d-%m-%Y %H-%M-%S.dmp"); + + auto hMinidumpFile = CreateFileA(stream.str().c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (hMinidumpFile) + { + MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo; + dumpExceptionInfo.ThreadId = GetCurrentThreadId(); + dumpExceptionInfo.ExceptionPointers = exceptionInfo; + dumpExceptionInfo.ClientPointers = false; - time_t time = std::time(nullptr); - tm currentTime = *std::localtime(&time); - std::stringstream stream; - stream << std::put_time(¤tTime, "R2Northstar/logs/nsdump%d-%m-%Y %H-%M-%S.dmp"); + MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hMinidumpFile, MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory), &dumpExceptionInfo, nullptr, nullptr); + CloseHandle(hMinidumpFile); + } + else + spdlog::error("Failed to write minidump file {}!", stream.str()); - auto hMinidumpFile = CreateFileA(stream.str().c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (hMinidumpFile) - { - MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo; - dumpExceptionInfo.ThreadId = GetCurrentThreadId(); - dumpExceptionInfo.ExceptionPointers = exceptionInfo; - dumpExceptionInfo.ClientPointers = false; + if (!IsDedicated()) + MessageBoxA(0, "Northstar has crashed! A crash log and dump can be found in R2Northstar/logs", "Northstar has crashed!", MB_ICONERROR | MB_OK); - MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hMinidumpFile, MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory), &dumpExceptionInfo, nullptr, nullptr); - CloseHandle(hMinidumpFile); } - else - spdlog::error("Failed to write minidump file {}!", stream.str()); - - if (!IsDedicated()) - MessageBoxA(0, "Northstar has crashed! A crash log and dump can be found in R2Northstar/logs", "Northstar has crashed!", MB_ICONERROR | MB_OK); logged = true; return EXCEPTION_EXECUTE_HANDLER; -- cgit v1.2.3 From 85c614c30d5f0608264aa42ffd9f11ede49dda6c Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 27 Dec 2021 02:24:06 +0000 Subject: make setplaylistvaroverride support multiple overrides since commandline is weird --- NorthstarDedicatedTest/playlist.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp index ef399347..fa7139d2 100644 --- a/NorthstarDedicatedTest/playlist.cpp +++ b/NorthstarDedicatedTest/playlist.cpp @@ -27,7 +27,8 @@ void SetPlaylistVarOverrideCommand(const CCommand& args) if (args.ArgC() < 3) return; - SetPlaylistVarOverride(args.Arg(1), args.Arg(2)); + for (int i = 1; i < args.ArgC(); i += 2) + SetPlaylistVarOverride(args.Arg(i), args.Arg(i + 1)); } char Onclc_SetPlaylistVarOverrideHook(void* a1, void* a2) @@ -51,7 +52,7 @@ void SetPlaylistVarOverrideHook(const char* varName, const char* value) void InitialisePlaylistHooks(HMODULE baseAddress) { RegisterConCommand("setplaylist", SetPlaylistCommand, "Sets the current playlist", FCVAR_NONE); - RegisterConCommand("setplaylistvaroverride", SetPlaylistVarOverrideCommand, "sets a playlist var override", FCVAR_NONE); + RegisterConCommand("setplaylistvaroverrides", SetPlaylistVarOverrideCommand, "sets a playlist var override", FCVAR_NONE); // note: clc_SetPlaylistVarOverride is pretty insecure, since it allows for entirely arbitrary playlist var overrides to be sent to the server // this is somewhat restricted on custom servers to prevent it being done outside of private matches, but ideally it should be disabled altogether, since the custom menus won't use it anyway // this should only really be accepted if you want vanilla client compatibility -- cgit v1.2.3 From c27bf9979b7524672e5315fe04d05cc93f6ee6af Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 27 Dec 2021 04:13:35 +0000 Subject: control server max players in playlist --- NorthstarDedicatedTest/playlist.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp index fa7139d2..47fb109c 100644 --- a/NorthstarDedicatedTest/playlist.cpp +++ b/NorthstarDedicatedTest/playlist.cpp @@ -9,8 +9,13 @@ typedef char(*Onclc_SetPlaylistVarOverrideType)(void* a1, void* a2); Onclc_SetPlaylistVarOverrideType Onclc_SetPlaylistVarOverride; + +typedef int(*GetCurrentGamemodeMaxPlayersType)(); +GetCurrentGamemodeMaxPlayersType GetCurrentGamemodeMaxPlayers; + // function type defined in gameutils.h SetPlaylistVarOverrideType SetPlaylistVarOverrideOriginal; +GetCurrentPlaylistVarType GetCurrentPlaylistVarOriginal; ConVar* Cvar_ns_use_clc_SetPlaylistVarOverride; @@ -49,6 +54,26 @@ void SetPlaylistVarOverrideHook(const char* varName, const char* value) SetPlaylistVarOverrideOriginal(varName, value); } +char* GetCurrentPlaylistVarHook(const char* varName, bool useOverrides) +{ + if (!useOverrides && !strcmp(varName, "max_players")) + useOverrides = true; + + return GetCurrentPlaylistVarOriginal(varName, useOverrides); +} + +int GetCurrentGamemodeMaxPlayersHook() +{ + char* maxPlayersStr = GetCurrentPlaylistVar("max_players", 0); + if (!maxPlayersStr) + return GetCurrentGamemodeMaxPlayers(); + + int maxPlayers = atoi(maxPlayersStr); + spdlog::info("Overwrote max_players to {}", maxPlayers); + + return maxPlayers; +} + void InitialisePlaylistHooks(HMODULE baseAddress) { RegisterConCommand("setplaylist", SetPlaylistCommand, "Sets the current playlist", FCVAR_NONE); @@ -61,6 +86,8 @@ void InitialisePlaylistHooks(HMODULE baseAddress) HookEnabler hook; ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x222180, &Onclc_SetPlaylistVarOverrideHook, reinterpret_cast(&Onclc_SetPlaylistVarOverride)); ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x18ED00, &SetPlaylistVarOverrideHook, reinterpret_cast(&SetPlaylistVarOverrideOriginal)); + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x18C680, &GetCurrentPlaylistVarHook, reinterpret_cast(&GetCurrentPlaylistVarOriginal)); + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x18C430, &GetCurrentGamemodeMaxPlayersHook, reinterpret_cast(&GetCurrentGamemodeMaxPlayers)); // patch to prevent clc_SetPlaylistVarOverride from being able to crash servers if we reach max overrides due to a call to Error (why is this possible respawn, wtf) // todo: add a warning for this -- cgit v1.2.3