aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack <66967891+ASpoonPlaysGames@users.noreply.github.com>2022-10-22 01:55:52 +0100
committerGitHub <noreply@github.com>2022-10-22 01:55:52 +0100
commit5a0f03a299e87252e5b943f85f33a92e18984c65 (patch)
treec4cfc6babcec6c779b11302423eea50b6e908f07
parentca6269431c5d1e4e91687b2ab7fd7ee2f311a2e0 (diff)
downloadNorthstarLauncher-1.10.0-rc4.tar.gz
NorthstarLauncher-1.10.0-rc4.zip
Allow rpaks to use starpaks that are in the mod's folder (#279)v1.10.0-rc4
* this works * read starpak entires from rpak headers * formatting * move logging to after function * Use str.empty instead of str != "" * change allocatedNewPath to std::string * merge conflict resolution part 2 * change to use int + add comment * better comments + init variable * path syntax + another comment * use goto to exit loop + improve commenting * implement requested changes * remove accidental diff * explanatory comment
-rw-r--r--NorthstarDLL/modmanager.cpp40
-rw-r--r--NorthstarDLL/modmanager.h3
-rw-r--r--NorthstarDLL/rpakfilesystem.cpp61
3 files changed, 93 insertions, 11 deletions
diff --git a/NorthstarDLL/modmanager.cpp b/NorthstarDLL/modmanager.cpp
index 05060902..07a197dd 100644
--- a/NorthstarDLL/modmanager.cpp
+++ b/NorthstarDLL/modmanager.cpp
@@ -469,6 +469,46 @@ void ModManager::LoadMods()
modPak.m_sPakName = pakName;
+ // read header of file and get the starpak paths
+ // this is done here as opposed to on starpak load because multiple rpaks can load a starpak
+ // and there is seemingly no good way to tell which rpak is causing the load of a starpak :/
+
+ std::ifstream rpakStream(file.path(), std::ios::binary);
+
+ // seek to the point in the header where the starpak reference size is
+ rpakStream.seekg(0x38, std::ios::beg);
+ int starpaksSize = 0;
+ rpakStream.read((char*)&starpaksSize, 2);
+
+ // seek to just after the header
+ rpakStream.seekg(0x58, std::ios::beg);
+ // read the starpak reference(s)
+ std::vector<char> buf(starpaksSize);
+ rpakStream.read(buf.data(), starpaksSize);
+
+ rpakStream.close();
+
+ // split the starpak reference(s) into strings to hash
+ std::string str = "";
+ for (int i = 0; i < starpaksSize; i++)
+ {
+ // if the current char is null, that signals the end of the current starpak path
+ if (buf[i] != 0x00)
+ {
+ str += buf[i];
+ }
+ else
+ {
+ // only add the string we are making if it isnt empty
+ if (!str.empty())
+ {
+ mod.StarpakPaths.push_back(STR_HASH(str));
+ spdlog::info("Mod {} registered starpak '{}'", mod.Name, str);
+ str = "";
+ }
+ }
+ }
+
// not using atm because we need to resolve path to rpak
// if (m_hasLoadedMods && modPak.m_bAutoLoad)
// g_pPakLoadManager->LoadPakAsync(pakName.c_str());
diff --git a/NorthstarDLL/modmanager.h b/NorthstarDLL/modmanager.h
index f622c675..9f57c69a 100644
--- a/NorthstarDLL/modmanager.h
+++ b/NorthstarDLL/modmanager.h
@@ -100,6 +100,9 @@ class Mod
std::vector<ModRpakEntry> Rpaks;
std::unordered_map<std::string, std::string>
RpakAliases; // paks we alias to other rpaks, e.g. to load sp_crashsite paks on the map mp_crashsite
+ std::vector<size_t> StarpakPaths; // starpaks that this mod contains
+ // there seems to be no nice way to get the rpak that is causing the load of a starpak?
+ // hashed with STR_HASH
std::unordered_map<std::string, std::string> DependencyConstants;
diff --git a/NorthstarDLL/rpakfilesystem.cpp b/NorthstarDLL/rpakfilesystem.cpp
index b1363589..5d5ac7ba 100644
--- a/NorthstarDLL/rpakfilesystem.cpp
+++ b/NorthstarDLL/rpakfilesystem.cpp
@@ -258,30 +258,69 @@ void*, __fastcall, (const char* pPath, void* pCallback))
// clang-format on
{
fs::path path(pPath);
- char* allocatedNewPath = nullptr;
+ std::string newPath = "";
+ fs::path filename = path.filename();
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_pModManager->m_ModFiles.find(g_pModManager->NormaliseModFilePath(fs::path("maps" / filename)));
if (modFile != g_pModManager->m_ModFiles.end())
{
- // need to allocate a new string for this
- std::string newPath = (modFile->second.m_pOwningMod->m_ModDirectory / "mod" / modFile->second.m_Path).string();
- allocatedNewPath = new char[newPath.size() + 1];
- strncpy_s(allocatedNewPath, newPath.size() + 1, newPath.c_str(), newPath.size());
- pPath = allocatedNewPath;
+ newPath = (modFile->second.m_pOwningMod->m_ModDirectory / "mod" / modFile->second.m_Path).string();
+ pPath = newPath.c_str();
}
}
+ else if (path.extension() == ".starpak")
+ {
+ // code for this is mostly stolen from above
+
+ // unfortunately I can't find a way to get the rpak that is causing this function call, so I have to
+ // store them on mod init and then compare the current path with the stored paths
+
+ // game adds r2\ to every path, so assume that a starpak path that begins with r2\paks\ is a vanilla one
+ // modded starpaks will be in the mod's paks folder (but can be in folders within the paks folder)
+
+ // this might look a bit confusing, but its just an iterator over the various directories in a path.
+ // path.begin() being the first directory, r2 in this case, which is guaranteed anyway,
+ // so increment the iterator with ++ to get the first actual directory, * just gets the actual value
+ // then we compare to "paks" to determine if it's a vanilla rpak or not
+ if (*++path.begin() != "paks")
+ {
+ // remove the r2\ from the start used for path lookups
+ std::string starpakPath = path.string().substr(3);
+ // hash the starpakPath to compare with stored entries
+ size_t hashed = STR_HASH(starpakPath);
+
+ // loop through all loaded mods
+ for (Mod& mod : g_pModManager->m_LoadedMods)
+ {
+ // ignore non-loaded mods
+ if (!mod.m_bEnabled)
+ continue;
- void* ret = ReadFileAsync(pPath, pCallback);
- if (allocatedNewPath)
- delete[] allocatedNewPath;
+ // loop through the stored starpak paths
+ for (size_t hash : mod.StarpakPaths)
+ {
+ if (hash == hashed)
+ {
+ // construct new path
+ newPath = (mod.m_ModDirectory / "paks" / starpakPath).string();
+ // set path to the new path
+ pPath = newPath.c_str();
+ goto LOG_STARPAK;
+ }
+ }
+ }
+ }
+
+ LOG_STARPAK:
+ spdlog::info("LoadStreamPak: {}", filename.string());
+ }
- return ret;
+ return ReadFileAsync(pPath, pCallback);
}
ON_DLL_LOAD("engine.dll", RpakFilesystem, (CModule module))