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