2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-27 03:18:17 +00:00

feat: unlinker auto paths (#848)

* chore: extract shared search paths code from modman

* feat: automatically detect search paths for game directories

* chore: adjust log levels for loading and unload search paths

* fix: move iwd to obj common
This commit is contained in:
Jan
2026-06-20 20:35:47 +02:00
committed by GitHub
parent b4477ac1a9
commit 087ce0c208
15 changed files with 336 additions and 292 deletions
+12 -114
View File
@@ -2,9 +2,6 @@
#include "Game/AutoSearchPaths.h"
#include "IObjLoader.h"
#include "SearchPath/IWD.h"
#include "SearchPath/SearchPathFilesystem.h"
#include "Utils/StringUtils.h"
#include "Web/Binds/ZoneBinds.h"
#include "Web/UiCommunication.h"
#include "ZoneLoading.h"
@@ -41,89 +38,15 @@ namespace
std::string m_zone_name;
double m_last_progress;
};
std::unique_ptr<ISearchPath> CreateSearchPath(const std::string& searchPathStr)
{
auto searchPath = std::make_unique<SearchPathFilesystem>(searchPathStr);
con::debug("Loaded search path \"{}\"", searchPathStr);
SearchPaths searchPaths;
bool hasIwds = false;
std::filesystem::directory_iterator iterator(searchPathStr);
const auto end = fs::end(iterator);
for (auto i = fs::begin(iterator); i != end; ++i)
{
if (!i->is_regular_file())
continue;
auto extension = i->path().extension().string();
utils::MakeStringLowerCase(extension);
if (extension == ".iwd")
{
std::string iwdPath = i->path().string();
auto iwd = iwd::LoadFromFile(iwdPath);
if (iwd)
{
if (!hasIwds)
{
searchPaths.CommitSearchPath(std::move(searchPath));
hasIwds = true;
}
searchPaths.CommitSearchPath(std::move(iwd));
con::debug("Loaded search path \"{}\"", iwdPath);
}
}
}
if (hasIwds)
return std::make_unique<SearchPaths>(std::move(searchPaths));
return searchPath;
}
} // namespace
ContextSearchPath::ContextSearchPath(std::unique_ptr<ISearchPath> searchPath)
: m_search_path(std::move(searchPath)),
m_ref_count(1)
{
}
LoadedZone::LoadedZone(std::unique_ptr<Zone> zone, std::string filePath, std::vector<std::string> searchPaths)
: m_zone(std::move(zone)),
m_file_path(std::move(filePath)),
m_search_paths(std::move(searchPaths))
{
}
Zone& LoadedZone::GetZone()
{
return *m_zone;
}
const Zone& LoadedZone::GetZone() const
{
return *m_zone;
}
const std::string& LoadedZone::GetFilePath() const
{
return m_file_path;
}
const std::vector<std::string>& LoadedZone::GetSearchPaths() const
{
return m_search_paths;
}
void FastFileContext::Destroy()
{
// Unload all zones
m_loaded_zones.clear();
}
std::expected<LoadedZone*, std::string> FastFileContext::LoadFastFile(const std::string& path)
std::expected<LoadedZoneInformation*, std::string> FastFileContext::LoadFastFile(const std::string& path)
{
auto zone = ZoneLoading::LoadZone(path, std::make_unique<LoadingEventProgressReporter>(fs::path(path).filename().replace_extension().string()));
if (!zone)
@@ -133,24 +56,12 @@ std::expected<LoadedZone*, std::string> FastFileContext::LoadFastFile(const std:
{
std::lock_guard lock(m_search_path_lock);
for (const auto& searchPathStr : searchPathsForZone)
{
const auto existingSearchPath = m_context_search_paths.find(searchPathStr);
if (existingSearchPath == m_context_search_paths.end())
{
auto searchPath = CreateSearchPath(searchPathStr);
m_search_paths.IncludeSearchPath(searchPath.get());
m_context_search_paths.emplace(searchPathStr, std::make_unique<ContextSearchPath>(std::move(searchPath)));
}
else
{
existingSearchPath->second->m_ref_count++;
}
}
m_shared_search_paths.RefSearchPath(searchPathStr);
}
auto loadedZone = std::make_unique<LoadedZone>(std::move(*zone), path, std::move(searchPathsForZone));
auto loadedZone = std::make_unique<LoadedZoneInformation>(std::move(*zone), path, std::move(searchPathsForZone));
LoadedZone* loadedZonePtr;
LoadedZoneInformation* loadedZonePtr;
{
std::lock_guard lock(m_zone_lock);
loadedZonePtr = m_loaded_zones.emplace_back(std::move(loadedZone)).get();
@@ -158,7 +69,8 @@ std::expected<LoadedZone*, std::string> FastFileContext::LoadFastFile(const std:
{
std::shared_lock lock(m_search_path_lock);
IObjLoader::GetObjLoaderForGame(loadedZonePtr->GetZone().m_game_id)->LoadReferencedContainersForZone(m_search_paths, loadedZonePtr->GetZone());
auto* objLoader = IObjLoader::GetObjLoaderForGame(loadedZonePtr->GetZone().m_game_id);
objLoader->LoadReferencedContainersForZone(m_shared_search_paths.GetSearchPath(), loadedZonePtr->GetZone());
}
ui::NotifyZoneLoaded(*loadedZonePtr);
@@ -168,12 +80,12 @@ std::expected<LoadedZone*, std::string> FastFileContext::LoadFastFile(const std:
std::expected<void, std::string> FastFileContext::UnloadZone(const std::string& zoneName)
{
std::unique_ptr<LoadedZone> removedLoadedZone;
std::unique_ptr<LoadedZoneInformation> removedLoadedZone;
{
std::lock_guard lock(m_zone_lock);
const auto existingZone = std::ranges::find_if(m_loaded_zones,
[&zoneName](const std::unique_ptr<LoadedZone>& loadedZone)
[&zoneName](const std::unique_ptr<LoadedZoneInformation>& loadedZone)
{
return loadedZone->GetZone().m_name == zoneName;
});
@@ -197,32 +109,18 @@ std::expected<void, std::string> FastFileContext::UnloadZone(const std::string&
{
std::lock_guard lock(m_search_path_lock);
for (const auto& searchPathStr : removedLoadedZone->GetSearchPaths())
{
const auto existingSearchPath = m_context_search_paths.find(searchPathStr);
if (existingSearchPath != m_context_search_paths.end())
{
assert(existingSearchPath->second->m_ref_count > 0);
const auto newRefCount = --existingSearchPath->second->m_ref_count;
if (newRefCount == 0)
{
m_search_paths.RemoveSearchPath(existingSearchPath->second->m_search_path.get());
m_context_search_paths.erase(existingSearchPath);
con::debug("Unloaded search path \"{}\"", searchPathStr);
}
}
}
m_shared_search_paths.UnrefSearchPath(searchPathStr);
}
return {};
}
ReadAccess<const std::vector<std::unique_ptr<LoadedZone>>> FastFileContext::GetLoadedZones()
ReadAccess<const std::vector<std::unique_ptr<LoadedZoneInformation>>> FastFileContext::GetLoadedZones()
{
return ReadAccess<const std::vector<std::unique_ptr<LoadedZone>>>(std::shared_lock(m_zone_lock), m_loaded_zones);
return ReadAccess<const std::vector<std::unique_ptr<LoadedZoneInformation>>>(std::shared_lock(m_zone_lock), m_loaded_zones);
}
ReadAccess<ISearchPath> FastFileContext::GetSearchPaths()
{
return ReadAccess<ISearchPath>(std::shared_lock(m_search_path_lock), m_search_paths);
return ReadAccess(std::shared_lock(m_search_path_lock), m_shared_search_paths.GetSearchPath());
}
+6 -33
View File
@@ -1,41 +1,15 @@
#pragma once
#include "SearchPath/SearchPaths.h"
#include "SearchPath/SharedSearchPaths.h"
#include "Zone/LoadedZoneInformation.h"
#include "Zone/Zone.h"
#include <expected>
#include <memory>
#include <shared_mutex>
#include <string>
#include <unordered_map>
#include <vector>
class ContextSearchPath
{
public:
explicit ContextSearchPath(std::unique_ptr<ISearchPath> searchPath);
std::unique_ptr<ISearchPath> m_search_path;
unsigned m_ref_count;
};
class LoadedZone
{
public:
LoadedZone(std::unique_ptr<Zone> zone, std::string filePath, std::vector<std::string> searchPaths);
[[nodiscard]] Zone& GetZone();
[[nodiscard]] const Zone& GetZone() const;
[[nodiscard]] const std::string& GetFilePath() const;
[[nodiscard]] const std::vector<std::string>& GetSearchPaths() const;
private:
std::unique_ptr<Zone> m_zone;
std::string m_file_path;
std::vector<std::string> m_search_paths;
};
template<class T> class ReadAccess
{
public:
@@ -60,17 +34,16 @@ class FastFileContext
public:
void Destroy();
std::expected<LoadedZone*, std::string> LoadFastFile(const std::string& path);
std::expected<LoadedZoneInformation*, std::string> LoadFastFile(const std::string& path);
std::expected<void, std::string> UnloadZone(const std::string& zoneName);
ReadAccess<const std::vector<std::unique_ptr<LoadedZone>>> GetLoadedZones();
ReadAccess<const std::vector<std::unique_ptr<LoadedZoneInformation>>> GetLoadedZones();
ReadAccess<ISearchPath> GetSearchPaths();
private:
std::vector<std::unique_ptr<LoadedZone>> m_loaded_zones;
std::vector<std::unique_ptr<LoadedZoneInformation>> m_loaded_zones;
std::shared_mutex m_zone_lock;
SearchPaths m_search_paths;
std::unordered_map<std::string, std::unique_ptr<ContextSearchPath>> m_context_search_paths;
SharedSearchPaths m_shared_search_paths;
std::shared_mutex m_search_path_lock;
};