From bc3e633718dc4d8b3528ae62b1e67702f1a42b9c Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:32:56 +0100 Subject: rename convar defaultvalue to m_pszDefaultValue (#136) --- NorthstarDedicatedTest/convar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/convar.h b/NorthstarDedicatedTest/convar.h index 72dc1d3c..07e7704b 100644 --- a/NorthstarDedicatedTest/convar.h +++ b/NorthstarDedicatedTest/convar.h @@ -129,7 +129,7 @@ class ConVar }; ConCommandBase m_ConCommandBase{}; // 0x0000 - const char* defaultVal{}; // 0x0040 + const char* m_pszDefaultValue{}; // 0x0040 CVValue_t m_Value{}; // 0x0048 bool m_bHasMin{}; // 0x005C float m_fMinVal{}; // 0x0060 -- cgit v1.2.3 From 1de9ea495fbe0a73db670ee73c23fad844364b8b Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sat, 9 Apr 2022 01:13:31 +0100 Subject: add audio changes (#133) * add audio changes * use shared_mutex instead of atomic_int for waiting on audio loads --- NorthstarDedicatedTest/audio.cpp | 54 ++++++++++++++++++++++++++++++---------- NorthstarDedicatedTest/audio.h | 2 ++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/NorthstarDedicatedTest/audio.cpp b/NorthstarDedicatedTest/audio.cpp index d3201b89..7a2ae711 100644 --- a/NorthstarDedicatedTest/audio.cpp +++ b/NorthstarDedicatedTest/audio.cpp @@ -25,6 +25,11 @@ EventOverrideData::EventOverrideData() LoadedSuccessfully = false; } +// Empty stereo 48000 WAVE file +unsigned char EMPTY_WAVE[45] = {0x52, 0x49, 0x46, 0x46, 0x25, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, + 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x88, 0x58, + 0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x74, 0x00, 0x00, 0x00, 0x00}; + EventOverrideData::EventOverrideData(const std::string& data, const fs::path& path) { if (data.length() <= 0) @@ -184,8 +189,10 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa { if (file.is_regular_file() && file.path().extension().string() == ".wav") { + std::string pathString = file.path().string(); + // Open the file. - std::basic_ifstream wavStream(file.path().string(), std::ios::binary); + std::basic_ifstream wavStream(pathString, std::ios::binary); if (wavStream.fail()) { @@ -196,18 +203,40 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa // Get file size. wavStream.seekg(0, std::ios::end); size_t fileSize = wavStream.tellg(); - wavStream.seekg(0, std::ios::beg); + wavStream.close(); // Allocate enough memory for the file. + // blank out the memory for now, then read it later uint8_t* data = new uint8_t[fileSize]; - - // Read the file. - wavStream.read(data, fileSize); - + memcpy(data, EMPTY_WAVE, sizeof(EMPTY_WAVE)); Samples.push_back({fileSize, std::unique_ptr(data)}); - // Close the file. - wavStream.close(); + // thread off the file read + // should we spawn one thread per read? or should there be a cap to the number of reads at once? + std::thread readThread( + [pathString, fileSize, data] + { + std::shared_lock lock(g_CustomAudioManager.m_loadingMutex); + std::basic_ifstream wavStream(pathString, std::ios::binary); + + // would be weird if this got hit, since it would've worked previously + if (wavStream.fail()) + { + spdlog::error("Failed async read of audio sample {}", pathString); + return; + } + + // read from after the header first to preserve the empty header, then read the header last + wavStream.seekg(sizeof(EMPTY_WAVE), std::ios::beg); + wavStream.read(&data[sizeof(EMPTY_WAVE)], fileSize - sizeof(EMPTY_WAVE)); + wavStream.seekg(0, std::ios::beg); + wavStream.read(data, sizeof(EMPTY_WAVE)); + wavStream.close(); + + spdlog::info("Finished async read of audio sample {}", pathString); + }); + + readThread.detach(); } } @@ -289,6 +318,10 @@ void CustomAudioManager::ClearAudioOverrides() // this is cancer but it works Sleep(50); } + + // slightly (very) bad + // wait for all audio reads to complete so we don't kill preexisting audio buffers as we're writing to them + std::unique_lock lock(g_CustomAudioManager.m_loadingMutex); m_loadedAudioOverrides.clear(); m_loadedAudioOverridesRegex.clear(); @@ -297,11 +330,6 @@ void CustomAudioManager::ClearAudioOverrides() typedef bool (*LoadSampleMetadata_Type)(void* sample, void* audioBuffer, unsigned int audioBufferLength, int audioType); LoadSampleMetadata_Type LoadSampleMetadata_Original; -// Empty stereo 48000 WAVE file -unsigned char EMPTY_WAVE[45] = {0x52, 0x49, 0x46, 0x46, 0x25, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, - 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x88, 0x58, - 0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x74, 0x00, 0x00, 0x00, 0x00}; - template Iter select_randomly(Iter start, Iter end, RandomGenerator& g) { std::uniform_int_distribution<> dis(0, std::distance(start, end) - 1); diff --git a/NorthstarDedicatedTest/audio.h b/NorthstarDedicatedTest/audio.h index 3220d804..6ed3ce57 100644 --- a/NorthstarDedicatedTest/audio.h +++ b/NorthstarDedicatedTest/audio.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace fs = std::filesystem; @@ -39,6 +40,7 @@ class CustomAudioManager bool TryLoadAudioOverride(const fs::path&); void ClearAudioOverrides(); + std::shared_mutex m_loadingMutex; std::unordered_map> m_loadedAudioOverrides = {}; std::unordered_map> m_loadedAudioOverridesRegex = {}; }; -- cgit v1.2.3 From e070b8b610de10401d62fdeee1037c4d451d40dc Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sat, 9 Apr 2022 02:15:26 +0100 Subject: add rui_drawEnable (#134) * add rui_drawEnable * oops forgot to push vcxproj changes to branch * format clientruihooks.cpp --- .../NorthstarDedicatedTest.vcxproj | 2 ++ .../NorthstarDedicatedTest.vcxproj.filters | 6 ++++++ NorthstarDedicatedTest/clientruihooks.cpp | 24 ++++++++++++++++++++++ NorthstarDedicatedTest/clientruihooks.h | 2 ++ NorthstarDedicatedTest/dllmain.cpp | 2 ++ 5 files changed, 36 insertions(+) create mode 100644 NorthstarDedicatedTest/clientruihooks.cpp create mode 100644 NorthstarDedicatedTest/clientruihooks.h diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index e9a27ad9..be70b70b 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -114,6 +114,7 @@ + @@ -572,6 +573,7 @@ + diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 3cc20b58..4089f1ca 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -1503,6 +1503,9 @@ Header Files + + Header Files\Client + @@ -1664,6 +1667,9 @@ Source Files + + Source Files\Client + diff --git a/NorthstarDedicatedTest/clientruihooks.cpp b/NorthstarDedicatedTest/clientruihooks.cpp new file mode 100644 index 00000000..bc6c7aa7 --- /dev/null +++ b/NorthstarDedicatedTest/clientruihooks.cpp @@ -0,0 +1,24 @@ +#include "pch.h" +#include "clientruihooks.h" +#include "convar.h" + +ConVar* Cvar_rui_drawEnable; + +typedef char (*DrawRUIFuncType)(void* a1, float* a2); +DrawRUIFuncType DrawRUIFunc; + +char DrawRUIFuncHook(void* a1, float* a2) +{ + if (!Cvar_rui_drawEnable->GetBool()) + return 0; + + return DrawRUIFunc(a1, a2); +} + +void InitialiseEngineClientRUIHooks(HMODULE baseAddress) +{ + Cvar_rui_drawEnable = new ConVar("rui_drawEnable", "1", FCVAR_CLIENTDLL, "Controls whether RUI should be drawn"); + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0xFC500, &DrawRUIFuncHook, reinterpret_cast(&DrawRUIFunc)); +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/clientruihooks.h b/NorthstarDedicatedTest/clientruihooks.h new file mode 100644 index 00000000..967ccefe --- /dev/null +++ b/NorthstarDedicatedTest/clientruihooks.h @@ -0,0 +1,2 @@ +#pragma once +void InitialiseEngineClientRUIHooks(HMODULE baseAddress); \ No newline at end of file diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 22b9a673..b5e06e3a 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -40,6 +40,7 @@ #include "plugin_abi.h" #include "plugins.h" #include "clientvideooverrides.h" +#include "clientruihooks.h" #include #include "version.h" #include "pch.h" @@ -246,6 +247,7 @@ bool InitialiseNorthstar() AddDllLoadCallbackForClient("client.dll", InitialiseLocalChatWriter); AddDllLoadCallbackForClient("client.dll", InitialiseScriptServerToClientStringCommands); AddDllLoadCallbackForClient("client.dll", InitialiseClientVideoOverrides); + AddDllLoadCallbackForClient("engine.dll", InitialiseEngineClientRUIHooks); // audio hooks AddDllLoadCallbackForClient("client.dll", InitialiseMilesAudioHooks); -- cgit v1.2.3 From ebe15e0c2fcec917947342148d294c7438f80012 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sat, 9 Apr 2022 02:53:05 +0100 Subject: various rpak loading changes (#135) * various rpak loading changes * format rpakfilesystem.cpp --- NorthstarDedicatedTest/modmanager.cpp | 2 +- NorthstarDedicatedTest/modmanager.h | 2 +- NorthstarDedicatedTest/rpakfilesystem.cpp | 101 +++++++++++++++++++++++++++--- 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 0ac7e4b6..f28f87c6 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -380,7 +380,7 @@ void ModManager::LoadMods() modPak.m_bAutoLoad = !bUseRpakJson || (dRpakJson.HasMember("Preload") && dRpakJson["Preload"].IsObject() && dRpakJson["Preload"].HasMember(pakName) && dRpakJson["Preload"][pakName].IsTrue()); - modPak.m_sPakPath = pakName; + modPak.m_sPakName = pakName; // not using atm because we need to resolve path to rpak // if (m_hasLoadedMods && modPak.m_bAutoLoad) diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h index 7f12559f..798c2306 100644 --- a/NorthstarDedicatedTest/modmanager.h +++ b/NorthstarDedicatedTest/modmanager.h @@ -56,7 +56,7 @@ struct ModRpakEntry { public: bool m_bAutoLoad; - std::string m_sPakPath; + std::string m_sPakName; }; class Mod diff --git a/NorthstarDedicatedTest/rpakfilesystem.cpp b/NorthstarDedicatedTest/rpakfilesystem.cpp index 6853029b..e9d5f0c6 100644 --- a/NorthstarDedicatedTest/rpakfilesystem.cpp +++ b/NorthstarDedicatedTest/rpakfilesystem.cpp @@ -8,13 +8,16 @@ LoadCommonPaksForMapType LoadCommonPaksForMap; typedef void* (*LoadPakSyncType)(const char* path, void* unknownSingleton, int flags); typedef int (*LoadPakAsyncType)(const char* path, void* unknownSingleton, int flags, void* callback0, void* callback1); +typedef void* (*ReadFullFileFromDiskType)(const char* requestedPath, void* a2); // there are more i'm just too lazy to add struct PakLoadFuncs { - void* unknown[2]; + void* unk0[2]; LoadPakSyncType LoadPakSync; LoadPakAsyncType LoadPakAsync; + void* unk1[20]; + ReadFullFileFromDiskType ReadFullFileFromDisk; }; PakLoadFuncs* g_pakLoadApi; @@ -41,12 +44,8 @@ void HandlePakAliases(char** map) } } -bool bShouldPreload = true; void LoadPreloadPaks() { - // disable preloading while we're doing this - bShouldPreload = false; - // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks for (Mod& mod : g_ModManager->m_loadedMods) { @@ -58,19 +57,59 @@ void LoadPreloadPaks() for (ModRpakEntry& pak : mod.Rpaks) if (pak.m_bAutoLoad) - g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakPath).string().c_str()); + g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str()); } +} + +void LoadCustomMapPaks(char** pakName) +{ + // whether the vanilla game has this rpak + bool bHasOriginalPak = fs::exists(fs::path("./r2/paks") / *pakName); + + // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks + for (Mod& mod : g_ModManager->m_loadedMods) + { + if (!mod.Enabled) + continue; - bShouldPreload = true; + // need to get a relative path of mod to mod folder + fs::path modPakPath("./" / mod.ModDirectory / "paks"); + + for (ModRpakEntry& pak : mod.Rpaks) + { + if (!pak.m_bAutoLoad && !pak.m_sPakName.compare(*pakName)) + { + // if the game doesn't have the original pak, let it handle loading this one as if it was the one it was loading originally + if (!bHasOriginalPak) + { + *pakName = &pak.m_sPakName[0]; + bHasOriginalPak = true; + } + else + g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str()); + } + } + } } LoadPakSyncType LoadPakSyncOriginal; void* LoadPakSyncHook(char* path, void* unknownSingleton, int flags) { HandlePakAliases(&path); + // note: we don't handle loading any preloaded custom paks synchronously since LoadPakSync is never actually called in retail, just load // them async instead - LoadPreloadPaks(); + static bool bShouldLoadPaks = true; + if (bShouldLoadPaks) + { + // disable preloading while we're doing this + bShouldLoadPaks = false; + + LoadPreloadPaks(); + LoadCustomMapPaks(&path); + + bShouldLoadPaks = true; + } spdlog::info("LoadPakSync {}", path); return LoadPakSyncOriginal(path, unknownSingleton, flags); @@ -81,14 +120,56 @@ int LoadPakAsyncHook(char* path, void* unknownSingleton, int flags, void* callba { HandlePakAliases(&path); - if (bShouldPreload) + static bool bShouldLoadPaks = true; + if (bShouldLoadPaks) + { + // disable preloading while we're doing this + bShouldLoadPaks = false; + LoadPreloadPaks(); + LoadCustomMapPaks(&path); + + bShouldLoadPaks = true; + } int ret = LoadPakAsyncOriginal(path, unknownSingleton, flags, callback0, callback1); spdlog::info("LoadPakAsync {} {}", path, ret); return ret; } +// 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 all together? +ReadFullFileFromDiskType ReadFullFileFromDiskOriginal; +void* ReadFullFileFromDiskHook(const char* requestedPath, void* a2) +{ + fs::path path(requestedPath); + char* allocatedNewPath = nullptr; + + if (path.extension() == ".stbsp") + { + fs::path filename = path.filename(); + spdlog::info("LoadStreamBsp: {}", filename.string()); + + // resolve modded stbsp path so we can load mod stbsps + auto modFile = g_ModManager->m_modFiles.find(fs::path("maps" / filename).lexically_normal().string()); + if (modFile != g_ModManager->m_modFiles.end()) + { + // need to allocate a new string for this + std::string newPath = (modFile->second.owningMod->ModDirectory / "mod" / modFile->second.path).string(); + allocatedNewPath = new char[newPath.size() + 1]; + strncpy(allocatedNewPath, newPath.c_str(), newPath.size()); + allocatedNewPath[newPath.size() + 1] = '\0'; + requestedPath = allocatedNewPath; + } + } + + void* ret = ReadFullFileFromDiskOriginal(requestedPath, a2); + if (allocatedNewPath) + delete[] allocatedNewPath; + + return ret; +} + void InitialiseEngineRpakFilesystem(HMODULE baseAddress) { g_PakLoadManager = new PakLoadManager; @@ -99,4 +180,6 @@ void InitialiseEngineRpakFilesystem(HMODULE baseAddress) HookEnabler hook; ENABLER_CREATEHOOK(hook, g_pakLoadApi->LoadPakSync, &LoadPakSyncHook, reinterpret_cast(&LoadPakSyncOriginal)); ENABLER_CREATEHOOK(hook, g_pakLoadApi->LoadPakAsync, &LoadPakAsyncHook, reinterpret_cast(&LoadPakAsyncOriginal)); + ENABLER_CREATEHOOK( + hook, g_pakLoadApi->ReadFullFileFromDisk, &ReadFullFileFromDiskHook, reinterpret_cast(&ReadFullFileFromDiskOriginal)); } \ No newline at end of file -- cgit v1.2.3 From ce8a64e7fa0aabf70e8ce9c0f9bbdef6892f240d Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 12 Apr 2022 01:32:33 +0100 Subject: make toggleconsole FCVAR_DONTRECORD (#140) --- NorthstarDedicatedTest/sourceconsole.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/sourceconsole.cpp b/NorthstarDedicatedTest/sourceconsole.cpp index 1e2e2f20..7bc68598 100644 --- a/NorthstarDedicatedTest/sourceconsole.cpp +++ b/NorthstarDedicatedTest/sourceconsole.cpp @@ -48,7 +48,7 @@ void InitialiseConsoleOnInterfaceCreation() void InitialiseSourceConsole(HMODULE baseAddress) { g_SourceGameConsole = new SourceInterface("client.dll", "GameConsole004"); - RegisterConCommand("toggleconsole", ConCommand_toggleconsole, "toggles the console", FCVAR_NONE); + RegisterConCommand("toggleconsole", ConCommand_toggleconsole, "toggles the console", FCVAR_DONTRECORD); } // logging stuff -- cgit v1.2.3 From b60432c85cb6e37c4a8bcdddeded75d3b71213b3 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 12 Apr 2022 01:54:12 +0100 Subject: more changes to mod rpak loading (#139) * more changes to mod rpak loading * reformat --- NorthstarDedicatedTest/dedicated.cpp | 7 --- NorthstarDedicatedTest/rpakfilesystem.cpp | 80 ++++++++++++++++++++++++++----- NorthstarDedicatedTest/rpakfilesystem.h | 6 ++- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index c97ac91d..c00bed07 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -184,13 +184,6 @@ void InitialiseDedicated(HMODULE engineAddress) // NSMem::NOP(ea + 0x1C4E07, 5); //} - // not sure if this should be done, not loading ui at least is good, but should everything be gone? - { - // Host_Init - // change the number of rpaks to load from 6 to 1, so we only load common.rpak - NSMem::BytePatch(ea + 0x15653B + 1, "01"); - } - { // Host_Init // remove call to ui loading stuff diff --git a/NorthstarDedicatedTest/rpakfilesystem.cpp b/NorthstarDedicatedTest/rpakfilesystem.cpp index e9d5f0c6..b4ddcd1a 100644 --- a/NorthstarDedicatedTest/rpakfilesystem.cpp +++ b/NorthstarDedicatedTest/rpakfilesystem.cpp @@ -2,12 +2,14 @@ #include "rpakfilesystem.h" #include "hookutils.h" #include "modmanager.h" +#include "dedicated.h" typedef void* (*LoadCommonPaksForMapType)(char* map); LoadCommonPaksForMapType LoadCommonPaksForMap; typedef void* (*LoadPakSyncType)(const char* path, void* unknownSingleton, int flags); typedef int (*LoadPakAsyncType)(const char* path, void* unknownSingleton, int flags, void* callback0, void* callback1); +typedef void* (*UnloadPakType)(int pakHandle, void* callback); typedef void* (*ReadFullFileFromDiskType)(const char* requestedPath, void* a2); // there are more i'm just too lazy to add @@ -16,7 +18,9 @@ struct PakLoadFuncs void* unk0[2]; LoadPakSyncType LoadPakSync; LoadPakAsyncType LoadPakAsync; - void* unk1[20]; + void* unk1[2]; + UnloadPakType UnloadPak; + void* unk2[17]; ReadFullFileFromDiskType ReadFullFileFromDisk; }; @@ -25,7 +29,21 @@ void** pUnknownPakLoadSingleton; PakLoadManager* g_PakLoadManager; void PakLoadManager::LoadPakSync(const char* path) { g_pakLoadApi->LoadPakSync(path, *pUnknownPakLoadSingleton, 0); } -void PakLoadManager::LoadPakAsync(const char* path) { g_pakLoadApi->LoadPakAsync(path, *pUnknownPakLoadSingleton, 2, nullptr, nullptr); } +void PakLoadManager::LoadPakAsync(const char* path, bool bMarkForUnload) +{ + int handle = g_pakLoadApi->LoadPakAsync(path, *pUnknownPakLoadSingleton, 2, nullptr, nullptr); + + if (bMarkForUnload) + m_pakHandlesToUnload.push_back(handle); +} + +void PakLoadManager::UnloadPaks() +{ + for (int pakHandle : m_pakHandlesToUnload) + g_pakLoadApi->UnloadPak(pakHandle, nullptr); + + m_pakHandlesToUnload.clear(); +} void HandlePakAliases(char** map) { @@ -57,14 +75,14 @@ void LoadPreloadPaks() for (ModRpakEntry& pak : mod.Rpaks) if (pak.m_bAutoLoad) - g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str()); + g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), false); } } -void LoadCustomMapPaks(char** pakName) +void LoadCustomMapPaks(char** pakName, bool* bNeedToFreePakName) { // whether the vanilla game has this rpak - bool bHasOriginalPak = fs::exists(fs::path("./r2/paks") / *pakName); + bool bHasOriginalPak = fs::exists(fs::path("./r2/paks/Win64/") / *pakName); // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks for (Mod& mod : g_ModManager->m_loadedMods) @@ -82,11 +100,17 @@ void LoadCustomMapPaks(char** pakName) // if the game doesn't have the original pak, let it handle loading this one as if it was the one it was loading originally if (!bHasOriginalPak) { - *pakName = &pak.m_sPakName[0]; + std::string path = (modPakPath / pak.m_sPakName).string(); + *pakName = new char[path.size() + 1]; + strcpy(*pakName, &path[0]); + (*pakName)[path.size()] = '\0'; + bHasOriginalPak = true; + *bNeedToFreePakName = + true; // we can't free this memory until we're done with the pak, so let whatever's calling this deal with it } else - g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str()); + g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakName).string().c_str(), true); } } } @@ -97,6 +121,8 @@ void* LoadPakSyncHook(char* path, void* unknownSingleton, int flags) { HandlePakAliases(&path); + bool bNeedToFreePakName = false; + // note: we don't handle loading any preloaded custom paks synchronously since LoadPakSync is never actually called in retail, just load // them async instead static bool bShouldLoadPaks = true; @@ -106,13 +132,18 @@ void* LoadPakSyncHook(char* path, void* unknownSingleton, int flags) bShouldLoadPaks = false; LoadPreloadPaks(); - LoadCustomMapPaks(&path); + LoadCustomMapPaks(&path, &bNeedToFreePakName); bShouldLoadPaks = true; } spdlog::info("LoadPakSync {}", path); - return LoadPakSyncOriginal(path, unknownSingleton, flags); + void* ret = LoadPakSyncOriginal(path, unknownSingleton, flags); + + if (bNeedToFreePakName) + delete[] path; + + return ret; } LoadPakAsyncType LoadPakAsyncOriginal; @@ -120,6 +151,8 @@ int LoadPakAsyncHook(char* path, void* unknownSingleton, int flags, void* callba { HandlePakAliases(&path); + bool bNeedToFreePakName = false; + static bool bShouldLoadPaks = true; if (bShouldLoadPaks) { @@ -127,16 +160,40 @@ int LoadPakAsyncHook(char* path, void* unknownSingleton, int flags, void* callba bShouldLoadPaks = false; LoadPreloadPaks(); - LoadCustomMapPaks(&path); + LoadCustomMapPaks(&path, &bNeedToFreePakName); bShouldLoadPaks = true; + + // 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 (IsDedicated() && strncmp(path, "common", 6)) // dedicated only needs common and common_mp + return -1; } int ret = LoadPakAsyncOriginal(path, unknownSingleton, flags, callback0, callback1); spdlog::info("LoadPakAsync {} {}", path, ret); + + if (bNeedToFreePakName) + delete[] path; + return ret; } +UnloadPakType UnloadPakOriginal; +void* UnloadPakHook(int pakHandle, void* callback) +{ + static bool bShouldUnloadPaks = true; + if (bShouldUnloadPaks) + { + bShouldUnloadPaks = false; + g_PakLoadManager->UnloadPaks(); + bShouldUnloadPaks = true; + } + + spdlog::info("UnloadPak {}", pakHandle); + return UnloadPakOriginal(pakHandle, 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 all together? ReadFullFileFromDiskType ReadFullFileFromDiskOriginal; @@ -158,7 +215,7 @@ void* ReadFullFileFromDiskHook(const char* requestedPath, void* a2) std::string newPath = (modFile->second.owningMod->ModDirectory / "mod" / modFile->second.path).string(); allocatedNewPath = new char[newPath.size() + 1]; strncpy(allocatedNewPath, newPath.c_str(), newPath.size()); - allocatedNewPath[newPath.size() + 1] = '\0'; + allocatedNewPath[newPath.size()] = '\0'; requestedPath = allocatedNewPath; } } @@ -180,6 +237,7 @@ void InitialiseEngineRpakFilesystem(HMODULE baseAddress) HookEnabler hook; ENABLER_CREATEHOOK(hook, g_pakLoadApi->LoadPakSync, &LoadPakSyncHook, reinterpret_cast(&LoadPakSyncOriginal)); ENABLER_CREATEHOOK(hook, g_pakLoadApi->LoadPakAsync, &LoadPakAsyncHook, reinterpret_cast(&LoadPakAsyncOriginal)); + ENABLER_CREATEHOOK(hook, g_pakLoadApi->UnloadPak, &UnloadPakHook, reinterpret_cast(&UnloadPakOriginal)); ENABLER_CREATEHOOK( hook, g_pakLoadApi->ReadFullFileFromDisk, &ReadFullFileFromDiskHook, reinterpret_cast(&ReadFullFileFromDiskOriginal)); } \ No newline at end of file diff --git a/NorthstarDedicatedTest/rpakfilesystem.h b/NorthstarDedicatedTest/rpakfilesystem.h index 334104a9..3c104822 100644 --- a/NorthstarDedicatedTest/rpakfilesystem.h +++ b/NorthstarDedicatedTest/rpakfilesystem.h @@ -6,7 +6,11 @@ class PakLoadManager { public: void LoadPakSync(const char* path); - void LoadPakAsync(const char* path); + void LoadPakAsync(const char* path, bool bMarkForUnload); + void UnloadPaks(); + + private: + std::vector m_pakHandlesToUnload; }; extern PakLoadManager* g_PakLoadManager; \ No newline at end of file -- cgit v1.2.3 From bd10ff7cc472d265650cd7c4fc47037195ba4008 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 12 Apr 2022 01:56:04 +0100 Subject: make curl logging optional (#141) --- NorthstarDedicatedTest/masterserver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index ab6388c3..63ae49a9 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -25,6 +25,8 @@ ConVar* Cvar_ns_server_name; ConVar* Cvar_ns_server_desc; ConVar* Cvar_ns_server_password; +ConVar* Cvar_ns_curl_log_enable; + // Source ConVar ConVar* Cvar_hostname; @@ -169,7 +171,7 @@ RemoteServerInfo::RemoteServerInfo( void MasterServerManager::SetCommonHttpClientOptions(CURL* curl) { curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, Cvar_ns_curl_log_enable->GetBool()); curl_easy_setopt(curl, CURLOPT_USERAGENT, &NSUserAgent); // curl_easy_setopt(curl, CURLOPT_STDERR, stdout); if (CommandLine()->FindParm("-msinsecure")) // TODO: this check doesn't seem to work @@ -1276,6 +1278,8 @@ void InitialiseSharedMasterServer(HMODULE baseAddress) Cvar_ns_report_server_to_masterserver = new ConVar("ns_report_server_to_masterserver", "1", FCVAR_GAMEDLL, ""); Cvar_ns_report_sp_server_to_masterserver = new ConVar("ns_report_sp_server_to_masterserver", "0", FCVAR_GAMEDLL, ""); + Cvar_ns_curl_log_enable = new ConVar("ns_curl_log_enable", "0", FCVAR_NONE, ""); + Cvar_hostname = *(ConVar**)((char*)baseAddress + 0x1315bae8); g_MasterServerManager = new MasterServerManager; -- cgit v1.2.3 From 8d242da7981204ea61b4678741a7cfe73d337442 Mon Sep 17 00:00:00 2001 From: amione <57235791+xamionex@users.noreply.github.com> Date: Tue, 12 Apr 2022 22:46:55 +0200 Subject: Update ns_icon.ico (#127) --- LauncherInjector/ns_icon.ico | Bin 128581 -> 1441814 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/LauncherInjector/ns_icon.ico b/LauncherInjector/ns_icon.ico index ad7ded80..fc9ad166 100644 Binary files a/LauncherInjector/ns_icon.ico and b/LauncherInjector/ns_icon.ico differ -- cgit v1.2.3