Add load argument to unlinker to load zones before trying to unlink specified zones

this allows to make sure certain ipaks are loaded before dumping
This commit is contained in:
Jan 2021-03-27 16:45:30 +01:00
parent 7d4029b21f
commit 4f995751ce
10 changed files with 158 additions and 81 deletions

View File

@ -253,6 +253,7 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv)
return false; return false;
} }
// -l; --load
if (m_argument_parser.IsOptionSpecified(OPTION_LOAD)) if (m_argument_parser.IsOptionSpecified(OPTION_LOAD))
m_zones_to_load = m_argument_parser.GetParametersForOption(OPTION_LOAD); m_zones_to_load = m_argument_parser.GetParametersForOption(OPTION_LOAD);

View File

@ -36,6 +36,8 @@ class Unlinker::Impl
SearchPathFilesystem* m_last_zone_search_path; SearchPathFilesystem* m_last_zone_search_path;
std::set<std::string> m_absolute_search_paths; std::set<std::string> m_absolute_search_paths;
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
_NODISCARD bool ShouldLoadObj() const _NODISCARD bool ShouldLoadObj() const
{ {
return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST; return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST;
@ -102,7 +104,7 @@ class Unlinker::Impl
LoadSearchPath(m_last_zone_search_path); LoadSearchPath(m_last_zone_search_path);
} }
for(auto* iwd : IWD::Repository) for (auto* iwd : IWD::Repository)
{ {
searchPathsForZone.IncludeSearchPath(iwd); searchPathsForZone.IncludeSearchPath(iwd);
} }
@ -174,7 +176,7 @@ class Unlinker::Impl
} }
} }
if(!result) if (!result)
{ {
printf("Failed to find writer for zone definition file of zone \"%s\".\n", zone->m_name.c_str()); printf("Failed to find writer for zone definition file of zone \"%s\".\n", zone->m_name.c_str());
} }
@ -228,7 +230,7 @@ class Unlinker::Impl
context.m_zone = zone; context.m_zone = zone;
context.m_base_path = outputFolderPath; context.m_base_path = outputFolderPath;
if(m_args.m_use_gdt) if (m_args.m_use_gdt)
{ {
if (!OpenGdtFile(zone, zoneDefinitionFileFolder, gdtStream)) if (!OpenGdtFile(zone, zoneDefinitionFileFolder, gdtStream))
return false; return false;
@ -240,7 +242,7 @@ class Unlinker::Impl
ObjWriting::DumpZone(context); ObjWriting::DumpZone(context);
if(m_args.m_use_gdt) if (m_args.m_use_gdt)
{ {
context.m_gdt->EndStream(); context.m_gdt->EndStream();
gdtStream.close(); gdtStream.close();
@ -250,6 +252,101 @@ class Unlinker::Impl
return true; return true;
} }
bool LoadZones()
{
for (const auto& zonePath : m_args.m_zones_to_load)
{
if (!fs::is_regular_file(zonePath))
{
printf("Could not find file \"%s\".\n", zonePath.c_str());
continue;
}
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory);
searchPathsForZone.IncludeSearchPath(&m_search_paths);
auto zone = ZoneLoading::LoadZone(zonePath);
if (zone == nullptr)
{
printf("Failed to load zone \"%s\".\n", zonePath.c_str());
return false;
}
if (m_args.m_verbose)
{
printf("Loaded zone \"%s\"\n", zone->m_name.c_str());
}
if (ShouldLoadObj())
{
ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone.get());
ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone.get());
}
m_loaded_zones.emplace_back(std::move(zone));
}
return true;
}
void UnloadZones()
{
if (ShouldLoadObj())
{
for (auto& loadedZone : m_loaded_zones)
{
ObjLoading::UnloadContainersOfZone(loadedZone.get());
}
}
m_loaded_zones.clear();
}
bool UnlinkZones()
{
for (const auto& zonePath : m_args.m_zones_to_unlink)
{
if (!fs::is_regular_file(zonePath))
{
printf("Could not find file \"%s\".\n", zonePath.c_str());
continue;
}
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory);
searchPathsForZone.IncludeSearchPath(&m_search_paths);
auto zone = ZoneLoading::LoadZone(zonePath);
if (zone == nullptr)
{
printf("Failed to load zone \"%s\".\n", zonePath.c_str());
return false;
}
if (m_args.m_verbose)
{
printf("Loaded zone \"%s\"\n", zone->m_name.c_str());
}
if (ShouldLoadObj())
{
ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone.get());
ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone.get());
}
if (!HandleZone(zone.get()))
return false;
if (ShouldLoadObj())
ObjLoading::UnloadContainersOfZone(zone.get());
}
return true;
}
public: public:
Impl() Impl()
{ {
@ -267,51 +364,13 @@ public:
if (!BuildSearchPaths()) if (!BuildSearchPaths())
return false; return false;
for (const auto& zonePath : m_args.m_zones_to_load) if (!LoadZones())
{ return false;
if (!fs::is_regular_file(zonePath))
{
printf("Could not find file \"%s\".\n", zonePath.c_str());
continue;
}
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string(); const auto result = UnlinkZones();
auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory); UnloadZones();
searchPathsForZone.IncludeSearchPath(&m_search_paths); return result;
auto* zone = ZoneLoading::LoadZone(zonePath);
if (zone == nullptr)
{
printf("Failed to load zone \"%s\".\n", zonePath.c_str());
return false;
}
if (m_args.m_verbose)
{
printf("Loaded zone \"%s\"\n", zone->m_name.c_str());
}
if (ShouldLoadObj())
{
ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone);
ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone);
}
if (!HandleZone(zone))
{
return false;
}
if (ShouldLoadObj())
{
ObjLoading::UnloadContainersOfZone(zone);
}
delete zone;
}
return true;
} }
}; };

View File

@ -29,9 +29,17 @@ const CommandLineOption* const OPTION_MINIMAL_ZONE_FILE =
.WithDescription("Minimizes the size of the zone file output by only including assets that are not a dependency of another asset.") .WithDescription("Minimizes the size of the zone file output by only including assets that are not a dependency of another asset.")
.Build(); .Build();
const CommandLineOption* const OPTION_LIST = const CommandLineOption* const OPTION_LOAD =
CommandLineOption::Builder::Create() CommandLineOption::Builder::Create()
.WithShortName("l") .WithShortName("l")
.WithLongName("load")
.WithDescription("Loads an existing zone before trying to unlink any zone.")
.WithParameter("zonePath")
.Reusable()
.Build();
const CommandLineOption* const OPTION_LIST =
CommandLineOption::Builder::Create()
.WithLongName("list") .WithLongName("list")
.WithDescription("Lists the contents of a zone instead of writing them to the disk.") .WithDescription("Lists the contents of a zone instead of writing them to the disk.")
.Build(); .Build();
@ -69,6 +77,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]
OPTION_HELP, OPTION_HELP,
OPTION_VERBOSE, OPTION_VERBOSE,
OPTION_MINIMAL_ZONE_FILE, OPTION_MINIMAL_ZONE_FILE,
OPTION_LOAD,
OPTION_LIST, OPTION_LIST,
OPTION_OUTPUT_FOLDER, OPTION_OUTPUT_FOLDER,
OPTION_SEARCH_PATH, OPTION_SEARCH_PATH,
@ -146,8 +155,8 @@ bool UnlinkerArgs::ParseArgs(const int argc, const char** argv)
return false; return false;
} }
m_zones_to_load = m_argument_parser.GetArguments(); m_zones_to_unlink = m_argument_parser.GetArguments();
const size_t zoneCount = m_zones_to_load.size(); const size_t zoneCount = m_zones_to_unlink.size();
if (zoneCount < 1) if (zoneCount < 1)
{ {
// No zones to load specified... // No zones to load specified...
@ -162,7 +171,11 @@ bool UnlinkerArgs::ParseArgs(const int argc, const char** argv)
// -min; --minimal-zone // -min; --minimal-zone
m_minimal_zone_def = m_argument_parser.IsOptionSpecified(OPTION_MINIMAL_ZONE_FILE); m_minimal_zone_def = m_argument_parser.IsOptionSpecified(OPTION_MINIMAL_ZONE_FILE);
// -l; --list // -l; --load
if (m_argument_parser.IsOptionSpecified(OPTION_LOAD))
m_zones_to_load = m_argument_parser.GetParametersForOption(OPTION_LOAD);
// --list
if (m_argument_parser.IsOptionSpecified(OPTION_LIST)) if (m_argument_parser.IsOptionSpecified(OPTION_LIST))
m_task = ProcessingTask::LIST; m_task = ProcessingTask::LIST;

View File

@ -31,6 +31,7 @@ public:
}; };
std::vector<std::string> m_zones_to_load; std::vector<std::string> m_zones_to_load;
std::vector<std::string> m_zones_to_unlink;
std::set<std::string> m_user_search_paths; std::set<std::string> m_user_search_paths;
ProcessingTask m_task; ProcessingTask m_task;

View File

@ -159,12 +159,13 @@ public:
return nullptr; return nullptr;
// Create new zone // Create new zone
auto* zone = new Zone(fileName, 0, &g_GameIW4); auto zone = std::make_unique<Zone>(fileName, 0, &g_GameIW4);
zone->m_pools = std::make_unique<GameAssetPoolIW4>(zone, 0); auto* zonePtr = zone.get();
zone->m_pools = std::make_unique<GameAssetPoolIW4>(zonePtr, 0);
zone->m_language = GetZoneLanguage(fileName); zone->m_language = GetZoneLanguage(fileName);
// File is supported. Now setup all required steps for loading this file. // File is supported. Now setup all required steps for loading this file.
auto* zoneLoader = new ZoneLoader(zone); auto* zoneLoader = new ZoneLoader(std::move(zone));
SetupBlock(zoneLoader); SetupBlock(zoneLoader);
@ -185,7 +186,7 @@ public:
zoneLoader->AddLoadingStep(std::make_unique<StepAllocXBlocks>()); zoneLoader->AddLoadingStep(std::make_unique<StepAllocXBlocks>());
// Start of the zone content // Start of the zone content
zoneLoader->AddLoadingStep(std::make_unique<StepLoadZoneContent>(std::make_unique<ContentLoader>(), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); zoneLoader->AddLoadingStep(std::make_unique<StepLoadZoneContent>(std::make_unique<ContentLoader>(), zonePtr, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK));
// Return the fully setup zoneloader // Return the fully setup zoneloader
return zoneLoader; return zoneLoader;

View File

@ -2,6 +2,7 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <memory>
#include "Game/T6/T6.h" #include "Game/T6/T6.h"
#include "Game/T6/ZoneConstantsT6.h" #include "Game/T6/ZoneConstantsT6.h"
@ -178,12 +179,13 @@ public:
return nullptr; return nullptr;
// Create new zone // Create new zone
auto* zone = new Zone(fileName, 0, &g_GameT6); auto zone = std::make_unique<Zone>(fileName, 0, &g_GameT6);
zone->m_pools = std::make_unique<GameAssetPoolT6>(zone, 0); auto* zonePtr = zone.get();
zone->m_pools = std::make_unique<GameAssetPoolT6>(zonePtr, 0);
zone->m_language = GetZoneLanguage(fileName); zone->m_language = GetZoneLanguage(fileName);
// File is supported. Now setup all required steps for loading this file. // File is supported. Now setup all required steps for loading this file.
auto* zoneLoader = new ZoneLoader(zone); auto* zoneLoader = new ZoneLoader(std::move(zone));
SetupBlock(zoneLoader); SetupBlock(zoneLoader);
@ -201,7 +203,7 @@ public:
zoneLoader->AddLoadingStep(std::make_unique<StepAllocXBlocks>()); zoneLoader->AddLoadingStep(std::make_unique<StepAllocXBlocks>());
// Start of the zone content // Start of the zone content
zoneLoader->AddLoadingStep(std::make_unique<StepLoadZoneContent>(std::make_unique<ContentLoader>(), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); zoneLoader->AddLoadingStep(std::make_unique<StepLoadZoneContent>(std::make_unique<ContentLoader>(), zonePtr, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK));
if (isSecure) if (isSecure)
{ {

View File

@ -1,20 +1,21 @@
#include "ZoneLoader.h" #include "ZoneLoader.h"
#include "Exception/LoadingException.h"
#include "LoadingFileStream.h"
#include <algorithm> #include <algorithm>
ZoneLoader::ZoneLoader(Zone* zone) #include "Exception/LoadingException.h"
#include "LoadingFileStream.h"
ZoneLoader::ZoneLoader(std::unique_ptr<Zone> zone)
: m_processor_chain_dirty(false),
m_zone(std::move(zone))
{ {
m_zone = zone;
m_processor_chain_dirty = false;
} }
ILoadingStream* ZoneLoader::BuildLoadingChain(ILoadingStream* rootStream) ILoadingStream* ZoneLoader::BuildLoadingChain(ILoadingStream* rootStream)
{ {
auto* currentStream = rootStream; auto* currentStream = rootStream;
for(const auto& processor : m_processors) for (const auto& processor : m_processors)
{ {
processor->SetBaseStream(currentStream); processor->SetBaseStream(currentStream);
@ -50,9 +51,9 @@ void ZoneLoader::AddStreamProcessor(std::unique_ptr<StreamProcessor> streamProce
void ZoneLoader::RemoveStreamProcessor(StreamProcessor* streamProcessor) void ZoneLoader::RemoveStreamProcessor(StreamProcessor* streamProcessor)
{ {
for(auto i = m_processors.begin(); i < m_processors.end(); ++i) for (auto i = m_processors.begin(); i < m_processors.end(); ++i)
{ {
if(i->get() == streamProcessor) if (i->get() == streamProcessor)
{ {
m_processors.erase(i); m_processors.erase(i);
m_processor_chain_dirty = true; m_processor_chain_dirty = true;
@ -61,18 +62,18 @@ void ZoneLoader::RemoveStreamProcessor(StreamProcessor* streamProcessor)
} }
} }
Zone* ZoneLoader::LoadZone(std::istream& stream) std::unique_ptr<Zone> ZoneLoader::LoadZone(std::istream& stream)
{ {
LoadingFileStream fileStream(stream); LoadingFileStream fileStream(stream);
auto* endStream = BuildLoadingChain(&fileStream); auto* endStream = BuildLoadingChain(&fileStream);
try try
{ {
for(const auto& step : m_steps) for (const auto& step : m_steps)
{ {
step->PerformStep(this, endStream); step->PerformStep(this, endStream);
if(m_processor_chain_dirty) if (m_processor_chain_dirty)
{ {
endStream = BuildLoadingChain(&fileStream); endStream = BuildLoadingChain(&fileStream);
} }
@ -83,12 +84,10 @@ Zone* ZoneLoader::LoadZone(std::istream& stream)
const auto detailedMessage = e.DetailedMessage(); const auto detailedMessage = e.DetailedMessage();
printf("Loading fastfile failed: %s\n", detailedMessage.c_str()); printf("Loading fastfile failed: %s\n", detailedMessage.c_str());
delete m_zone;
return nullptr; return nullptr;
} }
m_zone->Register(); m_zone->Register();
return m_zone; return std::move(m_zone);
} }

View File

@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include <istream> #include <istream>
#include <memory>
class ILoadingStep; class ILoadingStep;
@ -17,14 +18,14 @@ class ZoneLoader
bool m_processor_chain_dirty; bool m_processor_chain_dirty;
Zone* m_zone; std::unique_ptr<Zone> m_zone;
ILoadingStream* BuildLoadingChain(ILoadingStream* rootStream); ILoadingStream* BuildLoadingChain(ILoadingStream* rootStream);
public: public:
std::vector<XBlock*> m_blocks; std::vector<XBlock*> m_blocks;
explicit ZoneLoader(Zone* zone); explicit ZoneLoader(std::unique_ptr<Zone> zone);
void AddXBlock(std::unique_ptr<XBlock> block); void AddXBlock(std::unique_ptr<XBlock> block);
void AddLoadingStep(std::unique_ptr<ILoadingStep> step); void AddLoadingStep(std::unique_ptr<ILoadingStep> step);
@ -32,5 +33,5 @@ public:
void RemoveStreamProcessor(StreamProcessor* streamProcessor); void RemoveStreamProcessor(StreamProcessor* streamProcessor);
Zone* LoadZone(std::istream& stream); std::unique_ptr<Zone> LoadZone(std::istream& stream);
}; };

View File

@ -16,7 +16,7 @@ IZoneLoaderFactory* ZoneLoaderFactories[]
new T6::ZoneLoaderFactory() new T6::ZoneLoaderFactory()
}; };
Zone* ZoneLoading::LoadZone(const std::string& path) std::unique_ptr<Zone> ZoneLoading::LoadZone(const std::string& path)
{ {
auto zoneName = fs::path(path).filename().replace_extension("").string(); auto zoneName = fs::path(path).filename().replace_extension("").string();
std::ifstream file(path, std::fstream::in | std::fstream::binary); std::ifstream file(path, std::fstream::in | std::fstream::binary);
@ -50,9 +50,9 @@ Zone* ZoneLoading::LoadZone(const std::string& path)
return nullptr; return nullptr;
} }
auto* loadedZone = zoneLoader->LoadZone(file); auto loadedZone = zoneLoader->LoadZone(file);
delete zoneLoader; delete zoneLoader;
file.close(); file.close();
return loadedZone; return std::move(loadedZone);
} }

View File

@ -6,5 +6,5 @@
class ZoneLoading class ZoneLoading
{ {
public: public:
static Zone* LoadZone(const std::string& path); static std::unique_ptr<Zone> LoadZone(const std::string& path);
}; };