From 8a1a2e97624d15617197248a5e292c5ead5e74a2 Mon Sep 17 00:00:00 2001 From: p0358 Date: Wed, 29 Dec 2021 05:48:33 +0100 Subject: add launcher.dll proxy option --- NorthstarDedicatedTest/dedicated.cpp | 5 +- NorthstarDedicatedTest/dllmain.cpp | 21 +- NorthstarDedicatedTest/gameutils.cpp | 20 +- NorthstarDedicatedTest/masterserver.cpp | 341 ++++++++++----------- NorthstarDedicatedTest/masterserver.h | 4 + R2Northstar.sln | 14 +- loader_launcher_proxy/Memory.cpp | 52 ++++ loader_launcher_proxy/Memory.h | 15 + loader_launcher_proxy/dllmain.cpp | 114 +++++++ loader_launcher_proxy/framework.h | 5 + .../loader_launcher_proxy.vcxproj | 178 +++++++++++ .../loader_launcher_proxy.vcxproj.filters | 39 +++ loader_launcher_proxy/pch.cpp | 5 + loader_launcher_proxy/pch.h | 17 + 14 files changed, 636 insertions(+), 194 deletions(-) create mode 100644 loader_launcher_proxy/Memory.cpp create mode 100644 loader_launcher_proxy/Memory.h create mode 100644 loader_launcher_proxy/dllmain.cpp create mode 100644 loader_launcher_proxy/framework.h create mode 100644 loader_launcher_proxy/loader_launcher_proxy.vcxproj create mode 100644 loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters create mode 100644 loader_launcher_proxy/pch.cpp create mode 100644 loader_launcher_proxy/pch.h diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 83a9950a..e628a011 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -6,7 +6,8 @@ bool IsDedicated() { - return CommandLine()->CheckParm("-dedicated"); + //return CommandLine()->CheckParm("-dedicated"); + return strstr(GetCommandLineA(), "-dedicated"); } // CDedidcatedExports defs @@ -209,7 +210,7 @@ void InitialiseDedicated(HMODULE engineAddress) TempReadWrite rw(ptr); // remove call to Shader_Connect - *ptr = 0x90; + *ptr = (char)0x90; *(ptr + 1) = (char)0x90; *(ptr + 2) = (char)0x90; *(ptr + 3) = (char)0x90; diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 78edb297..80fc3ca4 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -43,9 +43,10 @@ BOOL APIENTRY DllMain( HMODULE hModule, break; } - if (!initialised) - InitialiseNorthstar(); - initialised = true; + // pls no xD + //if (!initialised) + // InitialiseNorthstar(); + //initialised = true; return TRUE; } @@ -53,7 +54,8 @@ BOOL APIENTRY DllMain( HMODULE hModule, void WaitForDebugger(HMODULE baseAddress) { // earlier waitfordebugger call than is in vanilla, just so we can debug stuff a little easier - if (CommandLine()->CheckParm("-waitfordebugger")) + //if (CommandLine()->CheckParm("-waitfordebugger")) + if (strstr(GetCommandLineA(), "-waitfordebugger")) { spdlog::info("waiting for debugger..."); spdlog::info("{} bytes have been statically allocated", g_iStaticAllocated); @@ -66,6 +68,13 @@ void WaitForDebugger(HMODULE baseAddress) // in the future this will be called from launcher instead of dllmain void InitialiseNorthstar() { + if (initialised) + { + fprintf(stderr, "[WARN] Called InitialiseNorthstar more than once!\n"); + return; + } + initialised = true; + InitialiseLogging(); // apply initial hooks @@ -73,7 +82,7 @@ void InitialiseNorthstar() InitialiseInterfaceCreationHooks(); // adding a callback to tier0 won't work for some reason - AddDllLoadCallback("launcher.dll", InitialiseTier0GameUtilFunctions); + AddDllLoadCallback("launcher.org.dll", InitialiseTier0GameUtilFunctions); AddDllLoadCallback("engine.dll", WaitForDebugger); AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions); AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions); @@ -82,7 +91,7 @@ void InitialiseNorthstar() // dedi patches { AddDllLoadCallback("engine.dll", InitialiseDedicated); - AddDllLoadCallback("launcher.dll", InitialiseDedicatedOrigin); + AddDllLoadCallback("launcher.org.dll", InitialiseDedicatedOrigin); AddDllLoadCallback("server.dll", InitialiseDedicatedServerGameDLL); AddDllLoadCallback("materialsystem_dx11.dll", InitialiseDedicatedMaterialSystem); // this fucking sucks, but seemingly we somehow load after rtech_game???? unsure how, but because of this we have to apply patches here, not on rtech_game load diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp index 642c44e6..97011059 100644 --- a/NorthstarDedicatedTest/gameutils.cpp +++ b/NorthstarDedicatedTest/gameutils.cpp @@ -79,11 +79,17 @@ void InitialiseServerGameUtilFunctions(HMODULE baseAddress) void InitialiseTier0GameUtilFunctions(HMODULE baseAddress) { baseAddress = GetModuleHandleA("tier0.dll"); - - CreateGlobalMemAlloc = (CreateGlobalMemAllocType)GetProcAddress(baseAddress, "CreateGlobalMemAlloc"); - g_pMemAllocSingleton = CreateGlobalMemAlloc(); - - Error = (ErrorType)GetProcAddress(baseAddress, "Error"); - CommandLine = (CommandLineType)GetProcAddress(baseAddress, "CommandLine"); - Plat_FloatTime = (Plat_FloatTimeType)GetProcAddress(baseAddress, "Plat_FloatTime"); + if (!baseAddress) + throw "tier0.dll is not loaded"; + + CreateGlobalMemAlloc = reinterpret_cast(GetProcAddress(baseAddress, "CreateGlobalMemAlloc")); + IMemAlloc** ppMemAllocSingleton = reinterpret_cast(GetProcAddress(baseAddress, "g_pMemAllocSingleton")); + if (!ppMemAllocSingleton || !*ppMemAllocSingleton) + g_pMemAllocSingleton = CreateGlobalMemAlloc(); + else + g_pMemAllocSingleton = *ppMemAllocSingleton; + + Error = reinterpret_cast(GetProcAddress(baseAddress, "Error")); + CommandLine = reinterpret_cast(GetProcAddress(baseAddress, "CommandLine")); + Plat_FloatTime = reinterpret_cast(GetProcAddress(baseAddress, "Plat_FloatTime")); } \ No newline at end of file diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index 706f60ec..1ebb4c89 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -35,7 +35,7 @@ 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) +constexpr const char* HttplibErrorToString(httplib::Error error) { switch (error) { @@ -68,6 +68,15 @@ const char* HttplibErrorToString(httplib::Error error) return ""; } +void MasterServerManager::SetHttpClientOptions(httplib::Client& http) +{ + http.set_connection_timeout(25); + http.set_read_timeout(25); + http.set_write_timeout(25); + if (CommandLine()->CheckParm("-msinsecure")) + http.enable_server_certificate_verification(false); +} + 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 @@ -112,9 +121,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or std::thread requestThread([this, uidStr, tokenStr]() { httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); - http.set_connection_timeout(25); - http.set_read_timeout(25); - http.set_write_timeout(25); + SetHttpClientOptions(http); spdlog::info("Trying to authenticate with northstar masterserver for user {}", uidStr); @@ -153,7 +160,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or } // we goto this instead of returning so we always hit this - REQUEST_END_CLEANUP: + REQUEST_END_CLEANUP: m_bOriginAuthWithMasterServerInProgress = false; m_bOriginAuthWithMasterServerDone = true; }); @@ -175,11 +182,9 @@ void MasterServerManager::RequestServerList() m_requestingServerList = true; m_scriptRequestingServerList = true; - + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); - http.set_connection_timeout(25); - http.set_read_timeout(25); - http.set_write_timeout(25); + SetHttpClientOptions(http); spdlog::info("Requesting server list from {}", Cvar_ns_masterserver_hostname->m_pszString); @@ -222,15 +227,15 @@ void MasterServerManager::RequestServerList() } // todo: verify json props are fine before adding to m_remoteServers - if (!serverObj.HasMember("id") || !serverObj["id"].IsString() - || !serverObj.HasMember("name") || !serverObj["name"].IsString() + if (!serverObj.HasMember("id") || !serverObj["id"].IsString() + || !serverObj.HasMember("name") || !serverObj["name"].IsString() || !serverObj.HasMember("description") || !serverObj["description"].IsString() || !serverObj.HasMember("map") || !serverObj["map"].IsString() || !serverObj.HasMember("playlist") || !serverObj["playlist"].IsString() || !serverObj.HasMember("playerCount") || !serverObj["playerCount"].IsNumber() || !serverObj.HasMember("maxPlayers") || !serverObj["maxPlayers"].IsNumber() || !serverObj.HasMember("hasPassword") || !serverObj["hasPassword"].IsBool() - || !serverObj.HasMember("modInfo") || !serverObj["modInfo"].HasMember("Mods") || !serverObj["modInfo"]["Mods"].IsArray() ) + || !serverObj.HasMember("modInfo") || !serverObj["modInfo"].HasMember("Mods") || !serverObj["modInfo"]["Mods"].IsArray()) { spdlog::error("Failed reading masterserver response: malformed server object"); continue; @@ -281,7 +286,7 @@ void MasterServerManager::RequestServerList() std::sort(m_remoteServers.begin(), m_remoteServers.end(), [](RemoteServerInfo& a, RemoteServerInfo& b) { return a.playerCount > b.playerCount; - }); + }); } else { @@ -290,7 +295,7 @@ void MasterServerManager::RequestServerList() } // we goto this instead of returning so we always hit this - REQUEST_END_CLEANUP: + REQUEST_END_CLEANUP: m_requestingServerList = false; m_scriptRequestingServerList = false; }); @@ -306,11 +311,9 @@ void MasterServerManager::RequestMainMenuPromos() { while (m_bOriginAuthWithMasterServerInProgress || !m_bOriginAuthWithMasterServerDone) Sleep(500); - + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); - http.set_connection_timeout(25); - http.set_read_timeout(25); - http.set_write_timeout(25); + SetHttpClientOptions(http); if (auto result = http.Get("/client/mainmenupromos")) { @@ -342,7 +345,7 @@ void MasterServerManager::RequestMainMenuPromos() !mainMenuPromoJson["newInfo"].HasMember("Title1") || !mainMenuPromoJson["newInfo"]["Title1"].IsString() || !mainMenuPromoJson["newInfo"].HasMember("Title2") || !mainMenuPromoJson["newInfo"]["Title2"].IsString() || !mainMenuPromoJson["newInfo"].HasMember("Title3") || !mainMenuPromoJson["newInfo"]["Title3"].IsString() || - + !mainMenuPromoJson.HasMember("largeButton") || !mainMenuPromoJson["largeButton"].IsObject() || !mainMenuPromoJson["largeButton"].HasMember("Title") || !mainMenuPromoJson["largeButton"]["Title"].IsString() || !mainMenuPromoJson["largeButton"].HasMember("Text") || !mainMenuPromoJson["largeButton"]["Text"].IsString() || @@ -388,7 +391,7 @@ void MasterServerManager::RequestMainMenuPromos() m_successfullyConnected = false; } - REQUEST_END_CLEANUP: + REQUEST_END_CLEANUP: // nothing lol return; }); @@ -405,13 +408,11 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken m_authenticatingWithGameServer = true; m_scriptAuthenticatingWithGameServer = true; m_successfullyAuthenticatedWithGameServer = false; - + std::thread requestThread([this, uid, 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); + SetHttpClientOptions(http); if (auto result = http.Post(fmt::format("/client/auth_with_self?id={}&playerToken={}", uid, playerToken).c_str())) { @@ -469,14 +470,14 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken spdlog::error("Failed reading masterserver authentication response: malformed json object"); goto REQUEST_END_CLEANUP; } - + newAuthData.pdata[i++] = (char)byte.GetUint(); } std::lock_guard guard(g_ServerAuthenticationManager->m_authDataMutex); g_ServerAuthenticationManager->m_authData.clear(); g_ServerAuthenticationManager->m_authData.insert(std::make_pair(authInfoJson["authToken"].GetString(), newAuthData)); - + m_successfullyAuthenticatedWithGameServer = true; } else @@ -487,7 +488,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken m_scriptAuthenticatingWithGameServer = false; } - REQUEST_END_CLEANUP: + REQUEST_END_CLEANUP: m_authenticatingWithGameServer = false; m_scriptAuthenticatingWithGameServer = false; @@ -519,16 +520,14 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c Sleep(100); httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); - http.set_connection_timeout(25); - http.set_read_timeout(25); - http.set_write_timeout(25); + SetHttpClientOptions(http); spdlog::info("Attempting authentication with server of id \"{}\"", serverId); if (auto result = http.Post(fmt::format("/client/auth_with_server?id={}&playerToken={}&server={}&password={}", uid, playerToken, serverId, password).c_str())) { m_successfullyConnected = true; - + rapidjson::Document connectionInfoJson; connectionInfoJson.Parse(result->body.c_str()); @@ -580,7 +579,7 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c m_scriptAuthenticatingWithGameServer = false; } - REQUEST_END_CLEANUP: + REQUEST_END_CLEANUP: m_authenticatingWithGameServer = false; m_scriptAuthenticatingWithGameServer = false; }); @@ -602,113 +601,109 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name m_bRequireClientAuth = true; 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); + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); + SetHttpClientOptions(http); - m_ownServerId[0] = 0; + m_ownServerId[0] = 0; - std::string request; - if (*password) - request = fmt::format("/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}", port, authPort, name, description, map, playlist, maxPlayers, password); - else - request = fmt::format("/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password=", port, authPort, name, description, map, playlist, maxPlayers); + std::string request; + if (*password) + request = fmt::format("/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}", port, authPort, name, description, map, playlist, maxPlayers, password); + else + request = fmt::format("/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password=", port, authPort, name, description, map, playlist, maxPlayers); - // build modinfo obj - rapidjson::Document modinfoDoc; - modinfoDoc.SetObject(); - modinfoDoc.AddMember("Mods", rapidjson::Value(rapidjson::kArrayType), modinfoDoc.GetAllocator()); + // build modinfo obj + rapidjson::Document modinfoDoc; + modinfoDoc.SetObject(); + modinfoDoc.AddMember("Mods", rapidjson::Value(rapidjson::kArrayType), modinfoDoc.GetAllocator()); - int currentModIndex = 0; - for (Mod& mod : g_ModManager->m_loadedMods) - { - if (!mod.Enabled || (!mod.RequiredOnClient && !mod.Pdiff.size())) - continue; + int currentModIndex = 0; + for (Mod& mod : g_ModManager->m_loadedMods) + { + if (!mod.Enabled || (!mod.RequiredOnClient && !mod.Pdiff.size())) + continue; - modinfoDoc["Mods"].PushBack(rapidjson::Value(rapidjson::kObjectType), modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("Name", rapidjson::StringRef(&mod.Name[0]), modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("Version", rapidjson::StringRef(&mod.Version[0]), modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("RequiredOnClient", mod.RequiredOnClient, modinfoDoc.GetAllocator()); - modinfoDoc["Mods"][currentModIndex].AddMember("Pdiff", rapidjson::StringRef(&mod.Pdiff[0]), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"].PushBack(rapidjson::Value(rapidjson::kObjectType), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("Name", rapidjson::StringRef(&mod.Name[0]), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("Version", rapidjson::StringRef(&mod.Version[0]), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("RequiredOnClient", mod.RequiredOnClient, modinfoDoc.GetAllocator()); + modinfoDoc["Mods"][currentModIndex].AddMember("Pdiff", rapidjson::StringRef(&mod.Pdiff[0]), modinfoDoc.GetAllocator()); - currentModIndex++; - } + currentModIndex++; + } - rapidjson::StringBuffer buffer; - buffer.Clear(); - rapidjson::Writer writer(buffer); - modinfoDoc.Accept(writer); - const char* modInfoString = buffer.GetString(); + rapidjson::StringBuffer buffer; + buffer.Clear(); + rapidjson::Writer writer(buffer); + modinfoDoc.Accept(writer); + const char* modInfoString = buffer.GetString(); - httplib::MultipartFormDataItems requestItems = { - {"modinfo", std::string(modInfoString, buffer.GetSize()), "modinfo.json", "application/octet-stream"} - }; + httplib::MultipartFormDataItems requestItems = { + {"modinfo", std::string(modInfoString, buffer.GetSize()), "modinfo.json", "application/octet-stream"} + }; - if (auto result = http.Post(request.c_str(), requestItems)) - { - m_successfullyConnected = true; - - rapidjson::Document serverAddedJson; - serverAddedJson.Parse(result->body.c_str()); + if (auto result = http.Post(request.c_str(), requestItems)) + { + m_successfullyConnected = true; - if (serverAddedJson.HasParseError()) - { - spdlog::error("Failed reading masterserver authentication response: encountered parse error \"{}\"", rapidjson::GetParseError_En(serverAddedJson.GetParseError())); - return; - } + rapidjson::Document serverAddedJson; + serverAddedJson.Parse(result->body.c_str()); - if (!serverAddedJson.IsObject()) - { - spdlog::error("Failed reading masterserver authentication response: root object is not an object"); - return; - } + if (serverAddedJson.HasParseError()) + { + spdlog::error("Failed reading masterserver authentication response: encountered parse error \"{}\"", rapidjson::GetParseError_En(serverAddedJson.GetParseError())); + return; + } - if (serverAddedJson.HasMember("error")) - { - spdlog::error("Failed reading masterserver response: got fastify error response"); - spdlog::error(result->body); - return; - } + if (!serverAddedJson.IsObject()) + { + spdlog::error("Failed reading masterserver authentication response: root object is not an object"); + return; + } - if (!serverAddedJson["success"].IsTrue()) - { - spdlog::error("Adding server to masterserver failed: \"success\" is not true"); - return; - } + if (serverAddedJson.HasMember("error")) + { + spdlog::error("Failed reading masterserver response: got fastify error response"); + spdlog::error(result->body); + return; + } - if (!serverAddedJson.HasMember("id") || !serverAddedJson["id"].IsString()) - { - spdlog::error("Failed reading masterserver response: malformed json object"); - return; - } + if (!serverAddedJson["success"].IsTrue()) + { + spdlog::error("Adding server to masterserver failed: \"success\" is not true"); + return; + } - strncpy(m_ownServerId, serverAddedJson["id"].GetString(), sizeof(m_ownServerId)); - m_ownServerId[sizeof(m_ownServerId) - 1] = 0; + if (!serverAddedJson.HasMember("id") || !serverAddedJson["id"].IsString()) + { + spdlog::error("Failed reading masterserver response: malformed json object"); + return; + } + strncpy(m_ownServerId, serverAddedJson["id"].GetString(), sizeof(m_ownServerId)); + m_ownServerId[sizeof(m_ownServerId) - 1] = 0; - // heartbeat thread - // ideally this should actually be done in main thread, rather than on it's own thread, so it'd stop if server freezes - 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) - { - Sleep(15000); - http.Post(fmt::format("/server/heartbeat?id={}&playerCount={}", m_ownServerId, g_ServerAuthenticationManager->m_additionalPlayerData.size()).c_str()); - } - }); + // heartbeat thread + // ideally this should actually be done in main thread, rather than on it's own thread, so it'd stop if server freezes + std::thread heartbeatThread([this] { + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); + SetHttpClientOptions(http); - heartbeatThread.detach(); - } - else - { - spdlog::error("Failed adding self to server list: error {}", HttplibErrorToString(result.error())); - m_successfullyConnected = false; - } + while (*m_ownServerId) + { + Sleep(15000); + http.Post(fmt::format("/server/heartbeat?id={}&playerCount={}", m_ownServerId, g_ServerAuthenticationManager->m_additionalPlayerData.size()).c_str()); + } + }); + + heartbeatThread.detach(); + } + else + { + spdlog::error("Failed adding self to server list: error {}", HttplibErrorToString(result.error())); + m_successfullyConnected = false; + } }); requestThread.detach(); @@ -721,20 +716,18 @@ void MasterServerManager::UpdateServerMapAndPlaylist(char* map, char* playlist, return; 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); + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); + SetHttpClientOptions(http); - // 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())) - { - m_successfullyConnected = true; - } - else - { - m_successfullyConnected = false; - } + // 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())) + { + m_successfullyConnected = true; + } + else + { + m_successfullyConnected = false; + } }); requestThread.detach(); @@ -747,20 +740,18 @@ void MasterServerManager::UpdateServerPlayerCount(int playerCount) return; 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); + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); + SetHttpClientOptions(http); - // 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())) - { - m_successfullyConnected = true; - } - else - { - m_successfullyConnected = false; - } + // 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())) + { + m_successfullyConnected = true; + } + else + { + m_successfullyConnected = false; + } }); requestThread.detach(); @@ -778,26 +769,24 @@ 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_read_timeout(25); - http.set_write_timeout(25); + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); + SetHttpClientOptions(http); - httplib::MultipartFormDataItems requestItems = { - { "pdata", std::string(pdata, pdataSize), "file.pdata", "application/octet-stream"} - }; + httplib::MultipartFormDataItems requestItems = { + { "pdata", std::string(pdata, pdataSize), "file.pdata", "application/octet-stream"} + }; - // we dont process this at all atm, maybe do later, but atm not necessary - if (auto result = http.Post(fmt::format("/accounts/write_persistence?id={}&serverId={}", playerIdTemp, m_ownServerId).c_str(), requestItems)) - { - m_successfullyConnected = true; - } - else - { - m_successfullyConnected = false; - } + // we dont process this at all atm, maybe do later, but atm not necessary + if (auto result = http.Post(fmt::format("/accounts/write_persistence?id={}&serverId={}", playerIdTemp, m_ownServerId).c_str(), requestItems)) + { + m_successfullyConnected = true; + } + else + { + m_successfullyConnected = false; + } - m_savingPersistentData = false; + m_savingPersistentData = false; }); requestThread.detach(); @@ -810,22 +799,20 @@ void MasterServerManager::RemoveSelfFromServerList() return; 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); + httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString); + SetHttpClientOptions(http); - // 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())) - { - m_successfullyConnected = true; - } - else - { - m_successfullyConnected = false; - } + // 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())) + { + m_successfullyConnected = true; + } + else + { + m_successfullyConnected = false; + } - m_ownServerId[0] = 0; + m_ownServerId[0] = 0; }); requestThread.detach(); diff --git a/NorthstarDedicatedTest/masterserver.h b/NorthstarDedicatedTest/masterserver.h index e51477a2..b403b24a 100644 --- a/NorthstarDedicatedTest/masterserver.h +++ b/NorthstarDedicatedTest/masterserver.h @@ -1,5 +1,6 @@ #pragma once #include "convar.h" +#include "httplib.h" #include struct RemoteModInfo @@ -92,6 +93,9 @@ public: bool m_bHasMainMenuPromoData = false; MainMenuPromoData m_MainMenuPromoData; +private: + void SetHttpClientOptions(httplib::Client& http); + public: void ClearServerList(); void RequestServerList(); diff --git a/R2Northstar.sln b/R2Northstar.sln index 1b664dd9..fdc4d903 100644 --- a/R2Northstar.sln +++ b/R2Northstar.sln @@ -1,12 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30621.155 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Northstar", "NorthstarDedicatedTest\NorthstarDedicatedTest.vcxproj", "{CFAD2623-064F-453C-8196-79EE10292E32}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NorthstarLauncher", "LauncherInjector\LauncherInjector.vcxproj", "{0EA82CB0-53FE-4D4C-96DF-47FA970513D0}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader_launcher_proxy", "loader_launcher_proxy\loader_launcher_proxy.vcxproj", "{F65C322D-66DF-4AF1-B650-70221DE334C0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -30,6 +32,14 @@ Global {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x64.Build.0 = Release|x64 {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x86.ActiveCfg = Release|Win32 {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x86.Build.0 = Release|Win32 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x64.ActiveCfg = Debug|x64 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x64.Build.0 = Debug|x64 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x86.ActiveCfg = Debug|Win32 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x86.Build.0 = Debug|Win32 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.ActiveCfg = Release|x64 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.Build.0 = Release|x64 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x86.ActiveCfg = Release|Win32 + {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp new file mode 100644 index 00000000..d8dc1dc5 --- /dev/null +++ b/loader_launcher_proxy/Memory.cpp @@ -0,0 +1,52 @@ +#include "pch.h" +#include +#include +#include + +HMODULE hTier0Module; +IMemAlloc** g_ppMemAllocSingleton; + +void LoadTier0Handle() +{ + hTier0Module = GetModuleHandleA("tier0.dll"); + if (!hTier0Module) return; + + g_ppMemAllocSingleton = (IMemAlloc**)GetProcAddress(hTier0Module, "g_pMemAllocSingleton"); +} + +const int STATIC_ALLOC_SIZE = 4096; + +size_t g_iStaticAllocated = 0; +char pStaticAllocBuf[STATIC_ALLOC_SIZE]; + +// they should never be used here, except in LibraryLoadError + +void* operator new(size_t n) +{ + // allocate into static buffer + if (g_iStaticAllocated + n <= STATIC_ALLOC_SIZE) + { + void* ret = pStaticAllocBuf + g_iStaticAllocated; + g_iStaticAllocated += n; + return ret; + } + else + { + // try to fallback to g_pMemAllocSingleton + if (!hTier0Module) LoadTier0Handle(); + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); + else + throw "Cannot allocate"; + } +} + +void operator delete(void* p) +{ + // if it was allocated into the static buffer, just do nothing, safest way to deal with it + if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) + return; + + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p); +} diff --git a/loader_launcher_proxy/Memory.h b/loader_launcher_proxy/Memory.h new file mode 100644 index 00000000..928e403c --- /dev/null +++ b/loader_launcher_proxy/Memory.h @@ -0,0 +1,15 @@ +#pragma once + +class IMemAlloc +{ +public: + struct VTable + { + void* unknown[1]; + void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize); + void* unknown2[3]; + void(*Free) (IMemAlloc* memAlloc, void* pMem); + }; + + VTable* m_vtable; +}; diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp new file mode 100644 index 00000000..6e0d1f07 --- /dev/null +++ b/loader_launcher_proxy/dllmain.cpp @@ -0,0 +1,114 @@ +#include "pch.h" +#include +#include +#include +#include + +HMODULE hLauncherModule; +HMODULE hHookModule; + +using CreateInterfaceFn = void* (*)(const char* pName, int* pReturnCode); + +// does not seem to ever be used +extern "C" _declspec(dllexport) void* __fastcall CreateInterface(const char* pName, int* pReturnCode) +{ + //AppSystemCreateInterfaceFn(pName, pReturnCode); + printf("external CreateInterface: name: %s\n", pName); + + static CreateInterfaceFn launcher_CreateInterface = (CreateInterfaceFn)GetProcAddress(hLauncherModule, "CreateInterface"); + auto res = launcher_CreateInterface(pName, pReturnCode); + + printf("external CreateInterface: return code: %p\n", res); + return res; +} + +bool GetExePathWide(wchar_t* dest, size_t destSize) +{ + if (!dest) return NULL; + if (destSize < MAX_PATH) return NULL; + + DWORD length = GetModuleFileNameW(NULL, dest, destSize); + return length && PathRemoveFileSpecW(dest); +} + +FARPROC GetLauncherMain() +{ + static FARPROC Launcher_LauncherMain; + if (!Launcher_LauncherMain) + Launcher_LauncherMain = GetProcAddress(hLauncherModule, "LauncherMain"); + return Launcher_LauncherMain; +} + +void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location) +{ + char text[2048]; + std::string message = std::system_category().message(dwMessageId); + sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs", libName, location, dwMessageId, message.c_str()); + MessageBoxA(GetForegroundWindow(), text, "Launcher Error", 0); +} + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +wchar_t exePath[4096]; +wchar_t dllPath[4096]; + +extern "C" _declspec(dllexport) void LauncherMain(__int64, __int64, __int64, uint32_t) +{ + { + + if (!GetExePathWide(exePath, 4096)) + { + MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + return; + } + + FARPROC Hook_Init = nullptr; + { + swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); + hHookModule = LoadLibraryExW(dllPath, 0i64, 8u); + if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); + if (!hHookModule || Hook_Init == nullptr) + { + LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath); + return; + } + } + + ((void (*)()) Hook_Init)(); + } + + { + swprintf_s(dllPath, L"%s\\bin\\x64_retail\\launcher.org.dll", exePath); + hLauncherModule = LoadLibraryExW(dllPath, 0i64, 8u); + if (!hLauncherModule) + { + LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath); + return; + } + } + + auto LauncherMain = GetLauncherMain(); + //auto result = ((__int64(__fastcall*)())LauncherMain)(); + //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64); + auto result = ((signed __int64(__fastcall*)(__int64, __int64, __int64, uint32_t))LauncherMain)(0i64, 0i64, 0i64, 0); +} + +// doubt that will help us here (in launcher.dll) though +extern "C" { + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; +} diff --git a/loader_launcher_proxy/framework.h b/loader_launcher_proxy/framework.h new file mode 100644 index 00000000..54b83e94 --- /dev/null +++ b/loader_launcher_proxy/framework.h @@ -0,0 +1,5 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj b/loader_launcher_proxy/loader_launcher_proxy.vcxproj new file mode 100644 index 00000000..ed6f5787 --- /dev/null +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj @@ -0,0 +1,178 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {f65c322d-66df-4af1-b650-70221de334c0} + loaderlauncherproxy + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + launcher + + + false + launcher + + + + Level3 + true + WIN32;_DEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp17 + + + Windows + true + false + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + Default + + + Windows + true + true + true + false + /HIGHENTROPYVA:NO %(AdditionalOptions) + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters new file mode 100644 index 00000000..519ed674 --- /dev/null +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/loader_launcher_proxy/pch.cpp b/loader_launcher_proxy/pch.cpp new file mode 100644 index 00000000..64b7eef6 --- /dev/null +++ b/loader_launcher_proxy/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/loader_launcher_proxy/pch.h b/loader_launcher_proxy/pch.h new file mode 100644 index 00000000..f9687185 --- /dev/null +++ b/loader_launcher_proxy/pch.h @@ -0,0 +1,17 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +#include "Memory.h" + +#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING + +// add headers that you want to pre-compile here +#include "framework.h" + +#endif //PCH_H -- cgit v1.2.3