mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-06-26 10:58:04 +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:
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
#include "Game/AutoSearchPaths.h"
|
#include "Game/AutoSearchPaths.h"
|
||||||
#include "IObjLoader.h"
|
#include "IObjLoader.h"
|
||||||
#include "SearchPath/IWD.h"
|
|
||||||
#include "SearchPath/SearchPathFilesystem.h"
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
#include "Web/Binds/ZoneBinds.h"
|
#include "Web/Binds/ZoneBinds.h"
|
||||||
#include "Web/UiCommunication.h"
|
#include "Web/UiCommunication.h"
|
||||||
#include "ZoneLoading.h"
|
#include "ZoneLoading.h"
|
||||||
@@ -41,89 +38,15 @@ namespace
|
|||||||
std::string m_zone_name;
|
std::string m_zone_name;
|
||||||
double m_last_progress;
|
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
|
} // 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()
|
void FastFileContext::Destroy()
|
||||||
{
|
{
|
||||||
// Unload all zones
|
// Unload all zones
|
||||||
m_loaded_zones.clear();
|
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()));
|
auto zone = ZoneLoading::LoadZone(path, std::make_unique<LoadingEventProgressReporter>(fs::path(path).filename().replace_extension().string()));
|
||||||
if (!zone)
|
if (!zone)
|
||||||
@@ -133,24 +56,12 @@ std::expected<LoadedZone*, std::string> FastFileContext::LoadFastFile(const std:
|
|||||||
{
|
{
|
||||||
std::lock_guard lock(m_search_path_lock);
|
std::lock_guard lock(m_search_path_lock);
|
||||||
for (const auto& searchPathStr : searchPathsForZone)
|
for (const auto& searchPathStr : searchPathsForZone)
|
||||||
{
|
m_shared_search_paths.RefSearchPath(searchPathStr);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
std::lock_guard lock(m_zone_lock);
|
||||||
loadedZonePtr = m_loaded_zones.emplace_back(std::move(loadedZone)).get();
|
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);
|
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);
|
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::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);
|
std::lock_guard lock(m_zone_lock);
|
||||||
const auto existingZone = std::ranges::find_if(m_loaded_zones,
|
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;
|
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);
|
std::lock_guard lock(m_search_path_lock);
|
||||||
for (const auto& searchPathStr : removedLoadedZone->GetSearchPaths())
|
for (const auto& searchPathStr : removedLoadedZone->GetSearchPaths())
|
||||||
{
|
m_shared_search_paths.UnrefSearchPath(searchPathStr);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
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()
|
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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "SearchPath/SearchPaths.h"
|
#include "SearchPath/SharedSearchPaths.h"
|
||||||
|
#include "Zone/LoadedZoneInformation.h"
|
||||||
#include "Zone/Zone.h"
|
#include "Zone/Zone.h"
|
||||||
|
|
||||||
#include <expected>
|
#include <expected>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#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
|
template<class T> class ReadAccess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -60,17 +34,16 @@ class FastFileContext
|
|||||||
public:
|
public:
|
||||||
void Destroy();
|
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);
|
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();
|
ReadAccess<ISearchPath> GetSearchPaths();
|
||||||
|
|
||||||
private:
|
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;
|
std::shared_mutex m_zone_lock;
|
||||||
|
|
||||||
SearchPaths m_search_paths;
|
SharedSearchPaths m_shared_search_paths;
|
||||||
std::unordered_map<std::string, std::unique_ptr<ContextSearchPath>> m_context_search_paths;
|
|
||||||
std::shared_mutex m_search_path_lock;
|
std::shared_mutex m_search_path_lock;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace
|
|||||||
auto& context = ModManContext::Get().m_fast_file;
|
auto& context = ModManContext::Get().m_fast_file;
|
||||||
const auto loadedZones = context.GetLoadedZones();
|
const auto loadedZones = context.GetLoadedZones();
|
||||||
const auto existingZone = std::ranges::find_if(loadedZones.Data(),
|
const auto existingZone = std::ranges::find_if(loadedZones.Data(),
|
||||||
[&zoneName](const std::unique_ptr<LoadedZone>& loadedZone)
|
[&zoneName](const std::unique_ptr<LoadedZoneInformation>& loadedZone)
|
||||||
{
|
{
|
||||||
return loadedZone->GetZone().m_name == zoneName;
|
return loadedZone->GetZone().m_name == zoneName;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ namespace
|
|||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneUnloadedDto, zoneName);
|
NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneUnloadedDto, zoneName);
|
||||||
|
|
||||||
ZoneDto CreateZoneDto(const LoadedZone& loadedZone)
|
ZoneDto CreateZoneDto(const LoadedZoneInformation& loadedZone)
|
||||||
{
|
{
|
||||||
return ZoneDto{
|
return ZoneDto{
|
||||||
.name = loadedZone.GetZone().m_name,
|
.name = loadedZone.GetZone().m_name,
|
||||||
@@ -149,7 +149,7 @@ namespace ui
|
|||||||
Notify(*ModManContext::Get().m_main_window, "zoneLoadProgress", dto);
|
Notify(*ModManContext::Get().m_main_window, "zoneLoadProgress", dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyZoneLoaded(const LoadedZone& loadedZone)
|
void NotifyZoneLoaded(const LoadedZoneInformation& loadedZone)
|
||||||
{
|
{
|
||||||
const ZoneLoadedDto dto{
|
const ZoneLoadedDto dto{
|
||||||
.zone = CreateZoneDto(loadedZone),
|
.zone = CreateZoneDto(loadedZone),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
void NotifyZoneLoadProgress(std::string zoneName, double percentage);
|
void NotifyZoneLoadProgress(std::string zoneName, double percentage);
|
||||||
void NotifyZoneLoaded(const LoadedZone& loadedZone);
|
void NotifyZoneLoaded(const LoadedZoneInformation& loadedZone);
|
||||||
void NotifyZoneUnloaded(std::string zoneName);
|
void NotifyZoneUnloaded(std::string zoneName);
|
||||||
|
|
||||||
void RegisterZoneBinds(webwindowed::commands_builder& commands);
|
void RegisterZoneBinds(webwindowed::commands_builder& commands);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "IWD.h"
|
#include "IWD.h"
|
||||||
|
|
||||||
#include "ObjLoading.h"
|
|
||||||
#include "Utils/FileToZlibWrapper.h"
|
#include "Utils/FileToZlibWrapper.h"
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
#include "SharedSearchPaths.h"
|
||||||
|
|
||||||
|
#include "SearchPath/IWD.h"
|
||||||
|
#include "SearchPathFilesystem.h"
|
||||||
|
#include "Utils/Logging/Log.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::unique_ptr<ISearchPath> CreateSearchPath(const std::string& searchPathStr)
|
||||||
|
{
|
||||||
|
auto searchPath = std::make_unique<SearchPathFilesystem>(searchPathStr);
|
||||||
|
con::info("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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasIwds)
|
||||||
|
return std::make_unique<SearchPaths>(std::move(searchPaths));
|
||||||
|
|
||||||
|
return searchPath;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SharedSearchPathEntry::SharedSearchPathEntry(std::unique_ptr<ISearchPath> searchPath)
|
||||||
|
: m_search_path(std::move(searchPath)),
|
||||||
|
m_ref_count(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedSearchPaths::SharedSearchPaths() = default;
|
||||||
|
|
||||||
|
SharedSearchPaths::~SharedSearchPaths()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedSearchPaths::Clear()
|
||||||
|
{
|
||||||
|
for (auto& entry : m_search_path_entries)
|
||||||
|
{
|
||||||
|
entry.second.reset();
|
||||||
|
con::info("Unloaded search path \"{}\"", entry.first);
|
||||||
|
}
|
||||||
|
m_search_path_entries.clear();
|
||||||
|
m_search_paths = SearchPaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISearchPath& SharedSearchPaths::GetSearchPath()
|
||||||
|
{
|
||||||
|
return m_search_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedSearchPaths::RefSearchPath(const std::string& searchPathStr)
|
||||||
|
{
|
||||||
|
const auto existingSearchPath = m_search_path_entries.find(searchPathStr);
|
||||||
|
if (existingSearchPath == m_search_path_entries.end())
|
||||||
|
{
|
||||||
|
auto searchPath = CreateSearchPath(searchPathStr);
|
||||||
|
m_search_paths.IncludeSearchPath(searchPath.get());
|
||||||
|
m_search_path_entries.emplace(searchPathStr, std::make_unique<SharedSearchPathEntry>(std::move(searchPath)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingSearchPath->second->m_ref_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedSearchPaths::UnrefSearchPath(const std::string& searchPathStr)
|
||||||
|
{
|
||||||
|
const auto existingSearchPath = m_search_path_entries.find(searchPathStr);
|
||||||
|
if (existingSearchPath != m_search_path_entries.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_search_path_entries.erase(existingSearchPath);
|
||||||
|
con::info("Unloaded search path \"{}\"", searchPathStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SearchPaths.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class SharedSearchPathEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SharedSearchPathEntry(std::unique_ptr<ISearchPath> searchPath);
|
||||||
|
|
||||||
|
std::unique_ptr<ISearchPath> m_search_path;
|
||||||
|
unsigned m_ref_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedSearchPaths
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SharedSearchPaths();
|
||||||
|
~SharedSearchPaths();
|
||||||
|
|
||||||
|
SharedSearchPaths(const SharedSearchPaths& other) = delete;
|
||||||
|
SharedSearchPaths(SharedSearchPaths&& other) noexcept = default;
|
||||||
|
SharedSearchPaths& operator=(const SharedSearchPaths& other) = delete;
|
||||||
|
SharedSearchPaths& operator=(SharedSearchPaths&& other) noexcept = default;
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
[[nodiscard]] ISearchPath& GetSearchPath();
|
||||||
|
|
||||||
|
void RefSearchPath(const std::string& searchPathStr);
|
||||||
|
void UnrefSearchPath(const std::string& searchPathStr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SearchPaths m_search_paths;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<SharedSearchPathEntry>> m_search_path_entries;
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "IW3/AutoSearchPathsIW3.h"
|
#include "IW3/AutoSearchPathsIW3.h"
|
||||||
#include "IW4/AutoSearchPathsIW4.h"
|
#include "IW4/AutoSearchPathsIW4.h"
|
||||||
|
#include "IW4/InfoString/InfoStringToStructConverter.h"
|
||||||
#include "IW5/AutoSearchPathsIW5.h"
|
#include "IW5/AutoSearchPathsIW5.h"
|
||||||
#include "T4/AutoSearchPathsT4.h"
|
#include "T4/AutoSearchPathsT4.h"
|
||||||
#include "T5/AutoSearchPathsT5.h"
|
#include "T5/AutoSearchPathsT5.h"
|
||||||
@@ -45,6 +46,8 @@ std::vector<std::string> AutoSearchPaths::GetSearchPathsForZonePath(const std::s
|
|||||||
if (!maybeGameRootFolder)
|
if (!maybeGameRootFolder)
|
||||||
return {folderName};
|
return {folderName};
|
||||||
|
|
||||||
|
con::debug("Detected game directory: {}", *maybeGameRootFolder);
|
||||||
|
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
const fs::path gameRootFolderPath(*maybeGameRootFolder);
|
const fs::path gameRootFolderPath(*maybeGameRootFolder);
|
||||||
|
|
||||||
|
|||||||
+105
-28
@@ -1,26 +1,86 @@
|
|||||||
#include "Unlinker.h"
|
#include "Unlinker.h"
|
||||||
|
|
||||||
#include "ContentLister/ContentPrinter.h"
|
#include "ContentLister/ContentPrinter.h"
|
||||||
|
#include "Game/AutoSearchPaths.h"
|
||||||
#include "IObjLoader.h"
|
#include "IObjLoader.h"
|
||||||
#include "ObjWriter.h"
|
#include "ObjWriter.h"
|
||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
#include "SearchPath/IWD.h"
|
|
||||||
#include "SearchPath/OutputPathFilesystem.h"
|
#include "SearchPath/OutputPathFilesystem.h"
|
||||||
|
#include "SearchPath/SharedSearchPaths.h"
|
||||||
#include "UnlinkerArgs.h"
|
#include "UnlinkerArgs.h"
|
||||||
#include "UnlinkerPaths.h"
|
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
#include "Zone/Definition/ZoneDefWriter.h"
|
#include "Zone/Definition/ZoneDefWriter.h"
|
||||||
|
#include "Zone/LoadedZoneInformation.h"
|
||||||
#include "ZoneLoading.h"
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
class ReferencedSearchPaths
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReferencedSearchPaths()
|
||||||
|
: m_shared_search_paths(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferencedSearchPaths(SharedSearchPaths& sharedSearchPaths, std::vector<std::string> searchPaths)
|
||||||
|
: m_shared_search_paths(&sharedSearchPaths),
|
||||||
|
m_search_paths(std::move(searchPaths))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~ReferencedSearchPaths()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferencedSearchPaths(const ReferencedSearchPaths& other) = delete;
|
||||||
|
|
||||||
|
ReferencedSearchPaths(ReferencedSearchPaths&& other) noexcept
|
||||||
|
: m_shared_search_paths(other.m_shared_search_paths),
|
||||||
|
m_search_paths(std::move(other.m_search_paths))
|
||||||
|
{
|
||||||
|
other.m_shared_search_paths = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferencedSearchPaths& operator=(const ReferencedSearchPaths& other) = delete;
|
||||||
|
|
||||||
|
ReferencedSearchPaths& operator=(ReferencedSearchPaths&& other) noexcept
|
||||||
|
{
|
||||||
|
m_shared_search_paths = other.m_shared_search_paths;
|
||||||
|
other.m_shared_search_paths = nullptr;
|
||||||
|
m_search_paths = std::move(other.m_search_paths);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
if (m_shared_search_paths)
|
||||||
|
{
|
||||||
|
for (const auto& searchPath : m_search_paths)
|
||||||
|
m_shared_search_paths->UnrefSearchPath(searchPath);
|
||||||
|
}
|
||||||
|
m_shared_search_paths = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedSearchPaths* m_shared_search_paths;
|
||||||
|
std::vector<std::string> m_search_paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<std::string> GetSearchPathsForZone(const std::string& zonePath, const GameId gameId)
|
||||||
|
{
|
||||||
|
return AutoSearchPaths::GetForGame(gameId)->GetSearchPathsForZonePath(zonePath);
|
||||||
|
}
|
||||||
|
|
||||||
class UnlinkerImpl : public Unlinker
|
class UnlinkerImpl : public Unlinker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -31,16 +91,18 @@ namespace
|
|||||||
|
|
||||||
bool Start() override
|
bool Start() override
|
||||||
{
|
{
|
||||||
UnlinkerPaths paths;
|
SharedSearchPaths paths;
|
||||||
if (!paths.LoadUserPaths(m_args))
|
for (const auto& userPath : m_args.m_user_search_paths)
|
||||||
return false;
|
paths.RefSearchPath(userPath);
|
||||||
|
|
||||||
if (!LoadZones(paths))
|
if (!LoadZones(paths))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto result = UnlinkZones(paths);
|
const auto result = UnlinkZones(paths);
|
||||||
|
|
||||||
UnloadZones();
|
UnloadZones(paths);
|
||||||
|
|
||||||
|
paths.Clear();
|
||||||
|
|
||||||
Summarize(result);
|
Summarize(result);
|
||||||
|
|
||||||
@@ -203,7 +265,7 @@ namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadZones(UnlinkerPaths& paths)
|
bool LoadZones(SharedSearchPaths& paths)
|
||||||
{
|
{
|
||||||
for (const auto& zonePath : m_args.m_zones_to_load)
|
for (const auto& zonePath : m_args.m_zones_to_load)
|
||||||
{
|
{
|
||||||
@@ -215,7 +277,6 @@ namespace
|
|||||||
|
|
||||||
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
|
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
|
||||||
|
|
||||||
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
if (!maybeZone)
|
if (!maybeZone)
|
||||||
{
|
{
|
||||||
@@ -225,44 +286,53 @@ namespace
|
|||||||
|
|
||||||
auto zone = std::move(*maybeZone);
|
auto zone = std::move(*maybeZone);
|
||||||
|
|
||||||
con::debug("Loaded zone \"{}\"", zone->m_name);
|
con::info("Loaded zone \"{}\"", zone->m_name);
|
||||||
|
|
||||||
|
auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory, zone->m_game_id);
|
||||||
|
for (const auto& searchPath : searchPathsForZone)
|
||||||
|
paths.RefSearchPath(searchPath);
|
||||||
|
|
||||||
if (ShouldLoadObj())
|
if (ShouldLoadObj())
|
||||||
{
|
{
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
||||||
objLoader->LoadReferencedContainersForZone(*searchPathsForZone, *zone);
|
objLoader->LoadReferencedContainersForZone(paths.GetSearchPath(), *zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loaded_zones.emplace_back(std::move(zone));
|
m_loaded_zones.emplace_back(
|
||||||
|
std::make_unique<LoadedZoneInformation>(std::move(zone), std::move(absoluteZoneDirectory), std::move(searchPathsForZone)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadZones()
|
void UnloadZones(SharedSearchPaths& paths)
|
||||||
{
|
{
|
||||||
for (auto i = m_loaded_zones.rbegin(); i != m_loaded_zones.rend(); ++i)
|
for (auto& loadedZone : std::ranges::reverse_view(m_loaded_zones))
|
||||||
{
|
{
|
||||||
auto& loadedZone = *i;
|
|
||||||
|
|
||||||
// Copy zone name since we deallocate before logging
|
// Copy zone name since we deallocate before logging
|
||||||
const auto zoneName = loadedZone->m_name;
|
const auto zoneName = loadedZone->GetZone().m_name;
|
||||||
|
|
||||||
if (ShouldLoadObj())
|
if (ShouldLoadObj())
|
||||||
{
|
{
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(loadedZone->m_game_id);
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(loadedZone->GetZone().m_game_id);
|
||||||
objLoader->UnloadContainersOfZone(*loadedZone);
|
objLoader->UnloadContainersOfZone(loadedZone->GetZone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& searchPath : loadedZone->GetSearchPaths())
|
||||||
|
paths.UnrefSearchPath(searchPath);
|
||||||
|
|
||||||
loadedZone.reset();
|
loadedZone.reset();
|
||||||
|
|
||||||
con::debug("Unloaded zone \"{}\"", zoneName);
|
con::info("Unloaded zone \"{}\"", zoneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loaded_zones.clear();
|
m_loaded_zones.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnlinkZones(UnlinkerPaths& paths) const
|
bool UnlinkZones(SharedSearchPaths& paths) const
|
||||||
{
|
{
|
||||||
|
ReferencedSearchPaths previousSearchPaths;
|
||||||
|
|
||||||
for (const auto& zonePath : m_args.m_zones_to_unlink)
|
for (const auto& zonePath : m_args.m_zones_to_unlink)
|
||||||
{
|
{
|
||||||
if (!fs::is_regular_file(zonePath))
|
if (!fs::is_regular_file(zonePath))
|
||||||
@@ -276,8 +346,6 @@ namespace
|
|||||||
zoneDirectory = fs::current_path();
|
zoneDirectory = fs::current_path();
|
||||||
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
||||||
|
|
||||||
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
|
||||||
|
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
if (!maybeZone)
|
if (!maybeZone)
|
||||||
{
|
{
|
||||||
@@ -287,13 +355,20 @@ namespace
|
|||||||
|
|
||||||
auto zone = std::move(*maybeZone);
|
auto zone = std::move(*maybeZone);
|
||||||
|
|
||||||
con::debug("Loaded zone \"{}\"", zone->m_name);
|
con::info("Loaded zone \"{}\"", zone->m_name);
|
||||||
|
|
||||||
|
auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory, zone->m_game_id);
|
||||||
|
for (const auto& searchPath : searchPathsForZone)
|
||||||
|
paths.RefSearchPath(searchPath);
|
||||||
|
|
||||||
|
previousSearchPaths.Clear();
|
||||||
|
previousSearchPaths = ReferencedSearchPaths(paths, std::move(searchPathsForZone));
|
||||||
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
||||||
if (ShouldLoadObj())
|
if (ShouldLoadObj())
|
||||||
objLoader->LoadReferencedContainersForZone(*searchPathsForZone, *zone);
|
objLoader->LoadReferencedContainersForZone(paths.GetSearchPath(), *zone);
|
||||||
|
|
||||||
if (!HandleZone(*searchPathsForZone, *zone))
|
if (!HandleZone(paths.GetSearchPath(), *zone))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ShouldLoadObj())
|
if (ShouldLoadObj())
|
||||||
@@ -302,9 +377,11 @@ namespace
|
|||||||
// Copy zone name for using it after freeing the zone
|
// Copy zone name for using it after freeing the zone
|
||||||
std::string zoneName = zone->m_name;
|
std::string zoneName = zone->m_name;
|
||||||
zone.reset();
|
zone.reset();
|
||||||
con::debug("Unloaded zone \"{}\"", zoneName);
|
con::info("Unloaded zone \"{}\"", zoneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
previousSearchPaths.Clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +392,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
UnlinkerArgs m_args;
|
UnlinkerArgs m_args;
|
||||||
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
|
std::vector<std::unique_ptr<LoadedZoneInformation>> m_loaded_zones;
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
#include "UnlinkerPaths.h"
|
|
||||||
|
|
||||||
#include "SearchPath/IWD.h"
|
|
||||||
#include "SearchPath/SearchPathFilesystem.h"
|
|
||||||
#include "Utils/Logging/Log.h"
|
|
||||||
#include "Utils/StringUtils.h"
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
bool UnlinkerPaths::LoadUserPaths(const UnlinkerArgs& args)
|
|
||||||
{
|
|
||||||
for (const auto& path : args.m_user_search_paths)
|
|
||||||
{
|
|
||||||
auto absolutePath = fs::absolute(path);
|
|
||||||
|
|
||||||
if (!fs::is_directory(absolutePath))
|
|
||||||
{
|
|
||||||
con::error("Could not find directory of search path: \"{}\"", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto searchPathName = absolutePath.string();
|
|
||||||
m_user_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathName));
|
|
||||||
m_specified_user_paths.emplace(std::move(searchPathName));
|
|
||||||
|
|
||||||
std::filesystem::directory_iterator iterator(absolutePath);
|
|
||||||
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")
|
|
||||||
{
|
|
||||||
auto iwd = iwd::LoadFromFile(i->path().string());
|
|
||||||
if (iwd)
|
|
||||||
m_user_paths.CommitSearchPath(std::move(iwd));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
con::info("{} SearchPaths{}", m_specified_user_paths.size(), !m_specified_user_paths.empty() ? ":" : "");
|
|
||||||
for (const auto& absoluteSearchPath : m_specified_user_paths)
|
|
||||||
con::info(" \"{}\"", absoluteSearchPath);
|
|
||||||
|
|
||||||
if (!m_specified_user_paths.empty())
|
|
||||||
con::info("");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<ISearchPath> UnlinkerPaths::GetSearchPathsForZone(const std::string& zonePath)
|
|
||||||
{
|
|
||||||
const auto absoluteZoneDirectory = fs::absolute(std::filesystem::path(zonePath).remove_filename());
|
|
||||||
const auto absoluteZoneDirectoryString = absoluteZoneDirectory.string();
|
|
||||||
if (m_last_zone_path != absoluteZoneDirectoryString)
|
|
||||||
{
|
|
||||||
m_last_zone_path = absoluteZoneDirectoryString;
|
|
||||||
m_last_zone_search_paths = SearchPaths();
|
|
||||||
m_last_zone_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absoluteZoneDirectoryString));
|
|
||||||
|
|
||||||
std::filesystem::directory_iterator iterator(absoluteZoneDirectory);
|
|
||||||
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")
|
|
||||||
{
|
|
||||||
auto iwd = iwd::LoadFromFile(i->path().string());
|
|
||||||
if (iwd)
|
|
||||||
m_last_zone_search_paths.CommitSearchPath(std::move(iwd));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = std::make_unique<SearchPaths>();
|
|
||||||
result->IncludeSearchPath(&m_last_zone_search_paths);
|
|
||||||
result->IncludeSearchPath(&m_user_paths);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "SearchPath/SearchPaths.h"
|
|
||||||
#include "UnlinkerArgs.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
class UnlinkerPaths
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool LoadUserPaths(const UnlinkerArgs& args);
|
|
||||||
std::unique_ptr<ISearchPath> GetSearchPathsForZone(const std::string& zonePath);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_last_zone_path;
|
|
||||||
SearchPaths m_last_zone_search_paths;
|
|
||||||
|
|
||||||
std::unordered_set<std::string> m_specified_user_paths;
|
|
||||||
SearchPaths m_user_paths;
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#include "LoadedZoneInformation.h"
|
||||||
|
|
||||||
|
LoadedZoneInformation::LoadedZoneInformation(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& LoadedZoneInformation::GetZone()
|
||||||
|
{
|
||||||
|
return *m_zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Zone& LoadedZoneInformation::GetZone() const
|
||||||
|
{
|
||||||
|
return *m_zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& LoadedZoneInformation::GetFilePath() const
|
||||||
|
{
|
||||||
|
return m_file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string>& LoadedZoneInformation::GetSearchPaths() const
|
||||||
|
{
|
||||||
|
return m_search_paths;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Zone.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class LoadedZoneInformation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LoadedZoneInformation(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;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user