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