mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-12-27 12:31:50 +00:00
Merge pull request #619 from Laupetin/fix/asset-references-in-global-assets
fix: asset references in global assets
This commit is contained in:
3
.github/workflows/ci.yaml
vendored
3
.github/workflows/ci.yaml
vendored
@@ -78,6 +78,7 @@ jobs:
|
|||||||
./ObjLoadingTests
|
./ObjLoadingTests
|
||||||
./ObjWritingTests
|
./ObjWritingTests
|
||||||
./ParserTests
|
./ParserTests
|
||||||
|
./SystemTests
|
||||||
./ZoneCodeGeneratorLibTests
|
./ZoneCodeGeneratorLibTests
|
||||||
./ZoneCommonTests
|
./ZoneCommonTests
|
||||||
|
|
||||||
@@ -138,6 +139,8 @@ jobs:
|
|||||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ParserTests
|
./ParserTests
|
||||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
|
./SystemTests
|
||||||
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ZoneCodeGeneratorLibTests
|
./ZoneCodeGeneratorLibTests
|
||||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ZoneCommonTests
|
./ZoneCommonTests
|
||||||
|
|||||||
14
premake5.lua
14
premake5.lua
@@ -129,11 +129,13 @@ group ""
|
|||||||
include "src/Common.lua"
|
include "src/Common.lua"
|
||||||
include "src/Cryptography.lua"
|
include "src/Cryptography.lua"
|
||||||
include "src/ImageConverter.lua"
|
include "src/ImageConverter.lua"
|
||||||
include "src/Linker.lua"
|
include "src/LinkerCli.lua"
|
||||||
|
include "src/Linking.lua"
|
||||||
include "src/ModMan.lua"
|
include "src/ModMan.lua"
|
||||||
include "src/Parser.lua"
|
include "src/Parser.lua"
|
||||||
include "src/RawTemplater.lua"
|
include "src/RawTemplater.lua"
|
||||||
include "src/Unlinker.lua"
|
include "src/UnlinkerCli.lua"
|
||||||
|
include "src/Unlinking.lua"
|
||||||
include "src/Utils.lua"
|
include "src/Utils.lua"
|
||||||
include "src/ZoneCode.lua"
|
include "src/ZoneCode.lua"
|
||||||
include "src/ZoneCodeGeneratorLib.lua"
|
include "src/ZoneCodeGeneratorLib.lua"
|
||||||
@@ -165,6 +167,8 @@ group "Components"
|
|||||||
ObjImage:project()
|
ObjImage:project()
|
||||||
ObjLoading:project()
|
ObjLoading:project()
|
||||||
ObjWriting:project()
|
ObjWriting:project()
|
||||||
|
Linking:project()
|
||||||
|
Unlinking:project()
|
||||||
group ""
|
group ""
|
||||||
|
|
||||||
-- Tools group: All projects that compile into the final tools
|
-- Tools group: All projects that compile into the final tools
|
||||||
@@ -175,8 +179,8 @@ group ""
|
|||||||
|
|
||||||
-- Tools group: All projects that compile into the final tools
|
-- Tools group: All projects that compile into the final tools
|
||||||
group "Tools"
|
group "Tools"
|
||||||
Linker:project()
|
LinkerCli:project()
|
||||||
Unlinker:project()
|
UnlinkerCli:project()
|
||||||
ImageConverter:project()
|
ImageConverter:project()
|
||||||
|
|
||||||
if _OPTIONS["modman"] then
|
if _OPTIONS["modman"] then
|
||||||
@@ -199,6 +203,7 @@ include "test/ObjLoadingTests.lua"
|
|||||||
include "test/ObjWritingTests.lua"
|
include "test/ObjWritingTests.lua"
|
||||||
include "test/ParserTestUtils.lua"
|
include "test/ParserTestUtils.lua"
|
||||||
include "test/ParserTests.lua"
|
include "test/ParserTests.lua"
|
||||||
|
include "test/SystemTests.lua"
|
||||||
include "test/ZoneCodeGeneratorLibTests.lua"
|
include "test/ZoneCodeGeneratorLibTests.lua"
|
||||||
include "test/ZoneCommonTests.lua"
|
include "test/ZoneCommonTests.lua"
|
||||||
|
|
||||||
@@ -212,6 +217,7 @@ group "Tests"
|
|||||||
ObjWritingTests:project()
|
ObjWritingTests:project()
|
||||||
ParserTestUtils:project()
|
ParserTestUtils:project()
|
||||||
ParserTests:project()
|
ParserTests:project()
|
||||||
|
SystemTests:project()
|
||||||
ZoneCodeGeneratorLibTests:project()
|
ZoneCodeGeneratorLibTests:project()
|
||||||
ZoneCommonTests:project()
|
ZoneCommonTests:project()
|
||||||
group ""
|
group ""
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ public:
|
|||||||
|
|
||||||
template<typename AssetType> struct AssetNameAccessor
|
template<typename AssetType> struct AssetNameAccessor
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
// static constexpr bool IS_SINGLETON = false;
|
// static constexpr bool IS_SINGLETON = false;
|
||||||
|
// using RETURN_TYPE = const char*&;
|
||||||
|
|
||||||
// const char*& operator()(AssetType::Type& asset)
|
// static RETURN_TYPE GetAssetName(assetType::Type& asset)
|
||||||
// {
|
// {
|
||||||
// throw std::runtime_error("Not implemented");
|
// throw std::runtime_error("Not implemented");
|
||||||
// }
|
// }
|
||||||
@@ -34,8 +34,9 @@ public:
|
|||||||
public: \
|
public: \
|
||||||
static_assert(std::is_base_of_v<IAssetBase, assetType>); \
|
static_assert(std::is_base_of_v<IAssetBase, assetType>); \
|
||||||
static constexpr bool IS_SINGLETON = false; \
|
static constexpr bool IS_SINGLETON = false; \
|
||||||
|
using RETURN_TYPE = const char*&; \
|
||||||
\
|
\
|
||||||
const char*& operator()(assetType::Type& asset) \
|
static RETURN_TYPE GetAssetName(assetType::Type& asset) \
|
||||||
{ \
|
{ \
|
||||||
return asset.nameProperty; \
|
return asset.nameProperty; \
|
||||||
} \
|
} \
|
||||||
@@ -47,10 +48,17 @@ public:
|
|||||||
public: \
|
public: \
|
||||||
static_assert(std::is_base_of_v<IAssetBase, assetType>); \
|
static_assert(std::is_base_of_v<IAssetBase, assetType>); \
|
||||||
static constexpr bool IS_SINGLETON = true; \
|
static constexpr bool IS_SINGLETON = true; \
|
||||||
|
using RETURN_TYPE = const char* const&; \
|
||||||
\
|
\
|
||||||
const char* const& operator()(assetType::Type& asset) \
|
static RETURN_TYPE GetAssetName(assetType::Type& asset) \
|
||||||
{ \
|
{ \
|
||||||
static const char* NAME = singletonName; \
|
static const char* NAME = singletonName; \
|
||||||
return NAME; \
|
return NAME; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename AssetType> AssetNameAccessor<AssetType>::RETURN_TYPE AssetName(typename AssetType::Type& asset)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
|
return AssetNameAccessor<AssetType>::GetAssetName(asset);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
Linker = {}
|
|
||||||
|
|
||||||
function Linker:include(includes)
|
|
||||||
if includes:handle(self:name()) then
|
|
||||||
includedirs {
|
|
||||||
path.join(ProjectFolder(), "Linker")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Linker:link(links)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function Linker:use()
|
|
||||||
dependson(self:name())
|
|
||||||
end
|
|
||||||
|
|
||||||
function Linker:name()
|
|
||||||
return "Linker"
|
|
||||||
end
|
|
||||||
|
|
||||||
function Linker:project()
|
|
||||||
local folder = ProjectFolder()
|
|
||||||
local includes = Includes:create()
|
|
||||||
local links = Links:create()
|
|
||||||
|
|
||||||
project(self:name())
|
|
||||||
targetdir(TargetDirectoryBin)
|
|
||||||
location "%{wks.location}/src/%{prj.name}"
|
|
||||||
kind "ConsoleApp"
|
|
||||||
language "C++"
|
|
||||||
|
|
||||||
files {
|
|
||||||
path.join(folder, "Linker/**.h"),
|
|
||||||
path.join(folder, "Linker/**.cpp")
|
|
||||||
}
|
|
||||||
|
|
||||||
self:include(includes)
|
|
||||||
Utils:include(includes)
|
|
||||||
ZoneLoading:include(includes)
|
|
||||||
ObjCompiling:include(includes)
|
|
||||||
ObjLoading:include(includes)
|
|
||||||
ObjWriting:include(includes)
|
|
||||||
ZoneWriting:include(includes)
|
|
||||||
|
|
||||||
Raw:use()
|
|
||||||
|
|
||||||
links:linkto(Utils)
|
|
||||||
links:linkto(ObjCompiling)
|
|
||||||
links:linkto(ZoneLoading)
|
|
||||||
links:linkto(ZoneWriting)
|
|
||||||
links:linkto(ObjLoading)
|
|
||||||
links:linkto(ObjWriting)
|
|
||||||
links:linkall()
|
|
||||||
end
|
|
||||||
@@ -1,480 +0,0 @@
|
|||||||
#include "Linker.h"
|
|
||||||
|
|
||||||
#include "LinkerArgs.h"
|
|
||||||
#include "LinkerPaths.h"
|
|
||||||
#include "ObjContainer/SoundBank/SoundBankWriter.h"
|
|
||||||
#include "ObjWriting.h"
|
|
||||||
#include "SearchPath/OutputPathFilesystem.h"
|
|
||||||
#include "SearchPath/SearchPaths.h"
|
|
||||||
#include "Utils/Logging/Log.h"
|
|
||||||
#include "Utils/ObjFileStream.h"
|
|
||||||
#include "Zone/AssetList/AssetList.h"
|
|
||||||
#include "Zone/AssetList/AssetListReader.h"
|
|
||||||
#include "Zone/Definition/ZoneDefinitionStream.h"
|
|
||||||
#include "ZoneCreation/ZoneCreationContext.h"
|
|
||||||
#include "ZoneCreation/ZoneCreator.h"
|
|
||||||
#include "ZoneLoading.h"
|
|
||||||
#include "ZoneWriting.h"
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class LinkerSearchPathContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LinkerSearchPathContext(const ILinkerSearchPathBuilder& searchPathBuilder)
|
|
||||||
: m_search_path_builder(searchPathBuilder)
|
|
||||||
{
|
|
||||||
m_independent_search_paths = m_search_path_builder.BuildIndependentSearchPaths();
|
|
||||||
if (m_independent_search_paths)
|
|
||||||
m_search_paths.IncludeSearchPath(m_independent_search_paths.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] ISearchPath& GetSearchPaths()
|
|
||||||
{
|
|
||||||
return m_search_paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadProjectSpecific(const std::string& projectName)
|
|
||||||
{
|
|
||||||
m_project_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProject(projectName);
|
|
||||||
if (m_project_specific_search_paths)
|
|
||||||
m_search_paths.IncludeSearchPath(m_project_specific_search_paths.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadProjectSpecific()
|
|
||||||
{
|
|
||||||
if (!m_project_specific_search_paths)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_search_paths.RemoveSearchPath(m_project_specific_search_paths.get());
|
|
||||||
m_project_specific_search_paths.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadGameSpecific(const std::string& projectName, const GameId game)
|
|
||||||
{
|
|
||||||
m_game_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProjectAndGame(projectName, game);
|
|
||||||
if (m_game_specific_search_paths)
|
|
||||||
m_search_paths.IncludeSearchPath(m_game_specific_search_paths.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadGameSpecific()
|
|
||||||
{
|
|
||||||
if (!m_game_specific_search_paths)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_search_paths.RemoveSearchPath(m_game_specific_search_paths.get());
|
|
||||||
m_game_specific_search_paths.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const ILinkerSearchPathBuilder& m_search_path_builder;
|
|
||||||
std::unique_ptr<ISearchPath> m_independent_search_paths;
|
|
||||||
std::unique_ptr<ISearchPath> m_project_specific_search_paths;
|
|
||||||
std::unique_ptr<ISearchPath> m_game_specific_search_paths;
|
|
||||||
SearchPaths m_search_paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LinkerPathManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LinkerPathManager(const LinkerArgs& args)
|
|
||||||
: m_linker_paths(ILinkerPaths::FromArgs(args)),
|
|
||||||
m_asset_paths(m_linker_paths->AssetSearchPaths()),
|
|
||||||
m_gdt_paths(m_linker_paths->GdtSearchPaths()),
|
|
||||||
m_source_paths(m_linker_paths->SourceSearchPaths())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<ILinkerPaths> m_linker_paths;
|
|
||||||
LinkerSearchPathContext m_asset_paths;
|
|
||||||
LinkerSearchPathContext m_gdt_paths;
|
|
||||||
LinkerSearchPathContext m_source_paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PathProjectContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PathProjectContext(LinkerPathManager& paths, const std::string& projectName)
|
|
||||||
: m_paths(paths)
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.LoadProjectSpecific(projectName);
|
|
||||||
m_paths.m_gdt_paths.LoadProjectSpecific(projectName);
|
|
||||||
m_paths.m_source_paths.LoadProjectSpecific(projectName);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PathProjectContext()
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.UnloadProjectSpecific();
|
|
||||||
m_paths.m_gdt_paths.UnloadProjectSpecific();
|
|
||||||
m_paths.m_source_paths.UnloadProjectSpecific();
|
|
||||||
}
|
|
||||||
|
|
||||||
PathProjectContext(const PathProjectContext& other) = delete;
|
|
||||||
PathProjectContext(PathProjectContext&& other) noexcept = delete;
|
|
||||||
PathProjectContext& operator=(const PathProjectContext& other) = delete;
|
|
||||||
PathProjectContext& operator=(PathProjectContext&& other) noexcept = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
LinkerPathManager& m_paths;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PathGameContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PathGameContext(LinkerPathManager& paths, const std::string& projectName, const GameId game)
|
|
||||||
: m_paths(paths)
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.LoadGameSpecific(projectName, game);
|
|
||||||
m_paths.m_gdt_paths.LoadGameSpecific(projectName, game);
|
|
||||||
m_paths.m_source_paths.LoadGameSpecific(projectName, game);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PathGameContext()
|
|
||||||
{
|
|
||||||
m_paths.m_asset_paths.UnloadGameSpecific();
|
|
||||||
m_paths.m_gdt_paths.UnloadGameSpecific();
|
|
||||||
m_paths.m_source_paths.UnloadGameSpecific();
|
|
||||||
}
|
|
||||||
|
|
||||||
PathGameContext(const PathGameContext& other) = delete;
|
|
||||||
PathGameContext(PathGameContext&& other) noexcept = delete;
|
|
||||||
PathGameContext& operator=(const PathGameContext& other) = delete;
|
|
||||||
PathGameContext& operator=(PathGameContext&& other) noexcept = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
LinkerPathManager& m_paths;
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
class LinkerImpl final : public Linker
|
|
||||||
{
|
|
||||||
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(LinkerPathManager& paths, const std::string& targetName, bool logMissing = true) const
|
|
||||||
{
|
|
||||||
auto& sourceSearchPath = paths.m_source_paths.GetSearchPaths();
|
|
||||||
std::unique_ptr<ZoneDefinition> zoneDefinition;
|
|
||||||
{
|
|
||||||
const auto definitionFileName = std::format("{}.zone", targetName);
|
|
||||||
const auto definitionStream = sourceSearchPath.Open(definitionFileName);
|
|
||||||
if (!definitionStream.IsOpen())
|
|
||||||
{
|
|
||||||
if (logMissing)
|
|
||||||
con::error("Could not find zone definition file for target \"{}\".", targetName);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, sourceSearchPath);
|
|
||||||
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!zoneDefinition)
|
|
||||||
{
|
|
||||||
con::error("Failed to read zone definition file for target \"{}\".", targetName);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return zoneDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadIgnoreEntries(LinkerPathManager& paths, const std::string& zoneName, const GameId game, AssetList& assetList) const
|
|
||||||
{
|
|
||||||
{
|
|
||||||
AssetListReader assetListReader(paths.m_source_paths.GetSearchPaths(), game);
|
|
||||||
const auto maybeReadAssetList = assetListReader.ReadAssetList(zoneName, false);
|
|
||||||
if (maybeReadAssetList)
|
|
||||||
{
|
|
||||||
assetList.m_entries.reserve(assetList.m_entries.size() + maybeReadAssetList->m_entries.size());
|
|
||||||
for (auto& entry : maybeReadAssetList->m_entries)
|
|
||||||
assetList.m_entries.emplace_back(std::move(entry));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto zoneDefinition = ReadZoneDefinition(paths, zoneName, false);
|
|
||||||
|
|
||||||
if (zoneDefinition)
|
|
||||||
{
|
|
||||||
assetList.m_entries.reserve(assetList.m_entries.size() + zoneDefinition->m_assets.size());
|
|
||||||
for (const auto& entry : zoneDefinition->m_assets)
|
|
||||||
assetList.m_entries.emplace_back(entry.m_asset_type, entry.m_asset_name, entry.m_is_reference);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessZoneDefinitionIgnores(LinkerPathManager& paths, const std::string& targetName, ZoneCreationContext& context) const
|
|
||||||
{
|
|
||||||
if (context.m_definition->m_ignores.empty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (const auto& ignore : context.m_definition->m_ignores)
|
|
||||||
{
|
|
||||||
if (ignore == targetName)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!ReadIgnoreEntries(paths, ignore, context.m_definition->m_game, context.m_ignored_assets))
|
|
||||||
{
|
|
||||||
con::error("Failed to read asset listing for ignoring assets of project \"{}\".", ignore);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool LoadGdtFilesFromZoneDefinition(std::vector<std::unique_ptr<Gdt>>& gdtList, const ZoneDefinition& zoneDefinition, ISearchPath* gdtSearchPath)
|
|
||||||
{
|
|
||||||
for (const auto& gdtName : zoneDefinition.m_gdts)
|
|
||||||
{
|
|
||||||
const auto gdtFile = gdtSearchPath->Open(std::format("{}.gdt", gdtName));
|
|
||||||
if (!gdtFile.IsOpen())
|
|
||||||
{
|
|
||||||
con::error("Failed to open file for gdt \"{}\"", gdtName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GdtReader gdtReader(*gdtFile.m_stream);
|
|
||||||
auto gdt = std::make_unique<Gdt>();
|
|
||||||
if (!gdtReader.Read(*gdt))
|
|
||||||
{
|
|
||||||
con::error("Failed to read gdt file \"{}\"", gdtName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdtList.emplace_back(std::move(gdt));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Zone> CreateZoneForDefinition(
|
|
||||||
LinkerPathManager& paths, const fs::path& outDir, const fs::path& cacheDir, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
|
||||||
{
|
|
||||||
ZoneCreationContext context(&zoneDefinition, &paths.m_asset_paths.GetSearchPaths(), outDir, cacheDir);
|
|
||||||
if (!ProcessZoneDefinitionIgnores(paths, targetName, context))
|
|
||||||
return nullptr;
|
|
||||||
if (!LoadGdtFilesFromZoneDefinition(context.m_gdt_files, zoneDefinition, &paths.m_gdt_paths.GetSearchPaths()))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return zone_creator::CreateZoneForDefinition(zoneDefinition.m_game, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool WriteZoneToFile(IOutputPath& outPath, const Zone& zone)
|
|
||||||
{
|
|
||||||
const auto stream = outPath.Open(std::format("{}.ff", zone.m_name));
|
|
||||||
if (!stream)
|
|
||||||
{
|
|
||||||
con::error("Failed to open file for zone: {}", zone.m_name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
con::info("Building zone \"{}\"", zone.m_name);
|
|
||||||
|
|
||||||
if (!ZoneWriting::WriteZone(*stream, zone))
|
|
||||||
{
|
|
||||||
con::error("Writing zone failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
con::info("Created zone \"{}\"", zone.m_name);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuildFastFile(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
|
||||||
{
|
|
||||||
const fs::path outDir(paths.m_linker_paths->BuildOutputFolderPath(projectName, zoneDefinition.m_game));
|
|
||||||
|
|
||||||
OutputPathFilesystem outputPath(outDir);
|
|
||||||
|
|
||||||
const fs::path cacheDir(paths.m_linker_paths->BuildCacheFolderPath(projectName, zoneDefinition.m_game));
|
|
||||||
SoundBankWriter::OutputPath = outDir;
|
|
||||||
|
|
||||||
const auto zone = CreateZoneForDefinition(paths, outDir, cacheDir, targetName, zoneDefinition);
|
|
||||||
auto result = zone != nullptr;
|
|
||||||
if (zone)
|
|
||||||
result = WriteZoneToFile(outputPath, *zone);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuildProject(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName) const
|
|
||||||
{
|
|
||||||
std::deque<std::string> targetsToBuild;
|
|
||||||
std::unordered_set<std::string> alreadyBuiltTargets;
|
|
||||||
|
|
||||||
targetsToBuild.emplace_back(targetName);
|
|
||||||
|
|
||||||
while (!targetsToBuild.empty())
|
|
||||||
{
|
|
||||||
const auto currentTarget = std::move(targetsToBuild.front());
|
|
||||||
targetsToBuild.pop_front();
|
|
||||||
alreadyBuiltTargets.emplace(currentTarget);
|
|
||||||
|
|
||||||
PathProjectContext projectContext(paths, projectName);
|
|
||||||
|
|
||||||
const auto zoneDefinition = ReadZoneDefinition(paths, targetName);
|
|
||||||
if (!zoneDefinition)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PathGameContext gameContext(paths, projectName, zoneDefinition->m_game);
|
|
||||||
|
|
||||||
if (!zoneDefinition->m_assets.empty())
|
|
||||||
{
|
|
||||||
if (!BuildFastFile(paths, projectName, targetName, *zoneDefinition))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (const auto& referencedTarget : zoneDefinition->m_targets_to_build)
|
|
||||||
{
|
|
||||||
if (alreadyBuiltTargets.find(referencedTarget) == alreadyBuiltTargets.end())
|
|
||||||
{
|
|
||||||
targetsToBuild.emplace_back(referencedTarget);
|
|
||||||
con::info("Building referenced target \"{}\"", referencedTarget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoadZones()
|
|
||||||
{
|
|
||||||
for (const auto& zonePath : m_args.m_zones_to_load)
|
|
||||||
{
|
|
||||||
if (!fs::is_regular_file(zonePath))
|
|
||||||
{
|
|
||||||
con::error("Could not find zone file to load \"{}\".", zonePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto zoneDirectory = fs::path(zonePath).remove_filename();
|
|
||||||
if (zoneDirectory.empty())
|
|
||||||
zoneDirectory = fs::current_path();
|
|
||||||
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
|
||||||
|
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
|
||||||
if (!maybeZone)
|
|
||||||
{
|
|
||||||
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto zone = std::move(*maybeZone);
|
|
||||||
|
|
||||||
con::debug("Loaded zone \"{}\"", zone->m_name);
|
|
||||||
|
|
||||||
m_loaded_zones.emplace_back(std::move(zone));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadZones()
|
|
||||||
{
|
|
||||||
for (auto i = m_loaded_zones.rbegin(); i != m_loaded_zones.rend(); ++i)
|
|
||||||
{
|
|
||||||
auto& loadedZone = *i;
|
|
||||||
std::string zoneName = loadedZone->m_name;
|
|
||||||
|
|
||||||
loadedZone.reset();
|
|
||||||
|
|
||||||
con::debug("Unloaded zone \"{}\"", zoneName);
|
|
||||||
}
|
|
||||||
m_loaded_zones.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetProjectAndTargetFromProjectSpecifier(const std::string& projectSpecifier, std::string& projectName, std::string& targetName)
|
|
||||||
{
|
|
||||||
const auto targetNameSeparatorIndex = projectSpecifier.find_first_of('/');
|
|
||||||
if (targetNameSeparatorIndex == std::string::npos)
|
|
||||||
{
|
|
||||||
projectName = projectSpecifier;
|
|
||||||
targetName = projectSpecifier;
|
|
||||||
}
|
|
||||||
else if (projectSpecifier.find_first_of('/', targetNameSeparatorIndex + 1) != std::string::npos)
|
|
||||||
{
|
|
||||||
con::error("Project specifier cannot have more than one target name: \"{}\"", projectSpecifier);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
projectName = projectSpecifier.substr(0, targetNameSeparatorIndex);
|
|
||||||
targetName = projectSpecifier.substr(targetNameSeparatorIndex + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (projectName.empty())
|
|
||||||
{
|
|
||||||
con::error("Project name cannot be empty: \"{}\"", projectSpecifier);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetName.empty())
|
|
||||||
{
|
|
||||||
con::error("Target name cannot be empty: \"{}\"", projectSpecifier);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool Start(const int argc, const char** argv) override
|
|
||||||
{
|
|
||||||
con::init();
|
|
||||||
|
|
||||||
auto shouldContinue = true;
|
|
||||||
if (!m_args.ParseArgs(argc, argv, shouldContinue))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!shouldContinue)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
LinkerPathManager paths(m_args);
|
|
||||||
|
|
||||||
if (!LoadZones())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto result = true;
|
|
||||||
for (const auto& projectSpecifier : m_args.m_project_specifiers_to_build)
|
|
||||||
{
|
|
||||||
std::string projectName;
|
|
||||||
std::string targetName;
|
|
||||||
if (!GetProjectAndTargetFromProjectSpecifier(projectSpecifier, projectName, targetName))
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BuildProject(paths, projectName, targetName))
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UnloadZones();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
LinkerArgs m_args;
|
|
||||||
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<Linker> Linker::Create()
|
|
||||||
{
|
|
||||||
return std::make_unique<LinkerImpl>();
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include "Linker.h"
|
|
||||||
|
|
||||||
int main(const int argc, const char** argv)
|
|
||||||
{
|
|
||||||
const auto linker = Linker::Create();
|
|
||||||
|
|
||||||
return linker->Start(argc, argv) ? 0 : 1;
|
|
||||||
}
|
|
||||||
49
src/LinkerCli.lua
Normal file
49
src/LinkerCli.lua
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
LinkerCli = {}
|
||||||
|
|
||||||
|
function LinkerCli:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
includedirs {
|
||||||
|
path.join(ProjectFolder(), "LinkerCli")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function LinkerCli:link(links)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function LinkerCli:use()
|
||||||
|
dependson(self:name())
|
||||||
|
end
|
||||||
|
|
||||||
|
function LinkerCli:name()
|
||||||
|
return "LinkerCli"
|
||||||
|
end
|
||||||
|
|
||||||
|
function LinkerCli:project()
|
||||||
|
local folder = ProjectFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
local links = Links:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryBin)
|
||||||
|
targetname "Linker"
|
||||||
|
location "%{wks.location}/src/%{prj.name}"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "LinkerCli/**.h"),
|
||||||
|
path.join(folder, "LinkerCli/**.cpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
Linking:include(includes)
|
||||||
|
|
||||||
|
Raw:use()
|
||||||
|
|
||||||
|
links:linkto(Utils)
|
||||||
|
links:linkto(Linking)
|
||||||
|
links:linkall()
|
||||||
|
end
|
||||||
19
src/LinkerCli/main.cpp
Normal file
19
src/LinkerCli/main.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "Linker.h"
|
||||||
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
|
int main(const int argc, const char** argv)
|
||||||
|
{
|
||||||
|
con::init();
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
auto shouldContinue = true;
|
||||||
|
if (!args.ParseArgs(argc, argv, shouldContinue))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!shouldContinue)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
|
||||||
|
return linker->Start() ? 0 : 1;
|
||||||
|
}
|
||||||
61
src/Linking.lua
Normal file
61
src/Linking.lua
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
Linking = {}
|
||||||
|
|
||||||
|
function Linking:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
ZoneCommon:include(includes)
|
||||||
|
includedirs {
|
||||||
|
path.join(ProjectFolder(), "Linking")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Linking:link(links)
|
||||||
|
links:add(self:name())
|
||||||
|
links:linkto(Utils)
|
||||||
|
links:linkto(ObjCompiling)
|
||||||
|
links:linkto(ZoneLoading)
|
||||||
|
links:linkto(ZoneWriting)
|
||||||
|
links:linkto(ObjLoading)
|
||||||
|
links:linkto(ObjWriting)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Linking:use()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function Linking:name()
|
||||||
|
return "Linking"
|
||||||
|
end
|
||||||
|
|
||||||
|
function Linking:project()
|
||||||
|
local folder = ProjectFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryLib)
|
||||||
|
location "%{wks.location}/src/%{prj.name}"
|
||||||
|
kind "StaticLib"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "Linking/**.h"),
|
||||||
|
path.join(folder, "Linking/**.cpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
vpaths {
|
||||||
|
["*"] = {
|
||||||
|
path.join(folder, "Linking")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCommon:use()
|
||||||
|
useSourceTemplating("Linking")
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
ZoneLoading:include(includes)
|
||||||
|
ObjCompiling:include(includes)
|
||||||
|
ObjLoading:include(includes)
|
||||||
|
ObjWriting:include(includes)
|
||||||
|
ZoneWriting:include(includes)
|
||||||
|
end
|
||||||
476
src/Linking/Linker.cpp
Normal file
476
src/Linking/Linker.cpp
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
#include "Linker.h"
|
||||||
|
|
||||||
|
#include "LinkerArgs.h"
|
||||||
|
#include "LinkerPaths.h"
|
||||||
|
#include "ObjContainer/SoundBank/SoundBankWriter.h"
|
||||||
|
#include "ObjWriting.h"
|
||||||
|
#include "SearchPath/OutputPathFilesystem.h"
|
||||||
|
#include "SearchPath/SearchPaths.h"
|
||||||
|
#include "Utils/Logging/Log.h"
|
||||||
|
#include "Utils/ObjFileStream.h"
|
||||||
|
#include "Zone/AssetList/AssetList.h"
|
||||||
|
#include "Zone/AssetList/AssetListReader.h"
|
||||||
|
#include "Zone/Definition/ZoneDefinitionStream.h"
|
||||||
|
#include "ZoneCreation/ZoneCreationContext.h"
|
||||||
|
#include "ZoneCreation/ZoneCreator.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
#include "ZoneWriting.h"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <fstream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class LinkerSearchPathContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LinkerSearchPathContext(const ILinkerSearchPathBuilder& searchPathBuilder)
|
||||||
|
: m_search_path_builder(searchPathBuilder)
|
||||||
|
{
|
||||||
|
m_independent_search_paths = m_search_path_builder.BuildIndependentSearchPaths();
|
||||||
|
if (m_independent_search_paths)
|
||||||
|
m_search_paths.IncludeSearchPath(m_independent_search_paths.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ISearchPath& GetSearchPaths()
|
||||||
|
{
|
||||||
|
return m_search_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadProjectSpecific(const std::string& projectName)
|
||||||
|
{
|
||||||
|
m_project_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProject(projectName);
|
||||||
|
if (m_project_specific_search_paths)
|
||||||
|
m_search_paths.IncludeSearchPath(m_project_specific_search_paths.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnloadProjectSpecific()
|
||||||
|
{
|
||||||
|
if (!m_project_specific_search_paths)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_search_paths.RemoveSearchPath(m_project_specific_search_paths.get());
|
||||||
|
m_project_specific_search_paths.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadGameSpecific(const std::string& projectName, const GameId game)
|
||||||
|
{
|
||||||
|
m_game_specific_search_paths = m_search_path_builder.BuildSearchPathsSpecificToProjectAndGame(projectName, game);
|
||||||
|
if (m_game_specific_search_paths)
|
||||||
|
m_search_paths.IncludeSearchPath(m_game_specific_search_paths.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnloadGameSpecific()
|
||||||
|
{
|
||||||
|
if (!m_game_specific_search_paths)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_search_paths.RemoveSearchPath(m_game_specific_search_paths.get());
|
||||||
|
m_game_specific_search_paths.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ILinkerSearchPathBuilder& m_search_path_builder;
|
||||||
|
std::unique_ptr<ISearchPath> m_independent_search_paths;
|
||||||
|
std::unique_ptr<ISearchPath> m_project_specific_search_paths;
|
||||||
|
std::unique_ptr<ISearchPath> m_game_specific_search_paths;
|
||||||
|
SearchPaths m_search_paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LinkerPathManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LinkerPathManager(const LinkerArgs& args)
|
||||||
|
: m_linker_paths(ILinkerPaths::FromArgs(args)),
|
||||||
|
m_asset_paths(m_linker_paths->AssetSearchPaths()),
|
||||||
|
m_gdt_paths(m_linker_paths->GdtSearchPaths()),
|
||||||
|
m_source_paths(m_linker_paths->SourceSearchPaths())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ILinkerPaths> m_linker_paths;
|
||||||
|
LinkerSearchPathContext m_asset_paths;
|
||||||
|
LinkerSearchPathContext m_gdt_paths;
|
||||||
|
LinkerSearchPathContext m_source_paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PathProjectContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PathProjectContext(LinkerPathManager& paths, const std::string& projectName)
|
||||||
|
: m_paths(paths)
|
||||||
|
{
|
||||||
|
m_paths.m_asset_paths.LoadProjectSpecific(projectName);
|
||||||
|
m_paths.m_gdt_paths.LoadProjectSpecific(projectName);
|
||||||
|
m_paths.m_source_paths.LoadProjectSpecific(projectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PathProjectContext()
|
||||||
|
{
|
||||||
|
m_paths.m_asset_paths.UnloadProjectSpecific();
|
||||||
|
m_paths.m_gdt_paths.UnloadProjectSpecific();
|
||||||
|
m_paths.m_source_paths.UnloadProjectSpecific();
|
||||||
|
}
|
||||||
|
|
||||||
|
PathProjectContext(const PathProjectContext& other) = delete;
|
||||||
|
PathProjectContext(PathProjectContext&& other) noexcept = delete;
|
||||||
|
PathProjectContext& operator=(const PathProjectContext& other) = delete;
|
||||||
|
PathProjectContext& operator=(PathProjectContext&& other) noexcept = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LinkerPathManager& m_paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PathGameContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PathGameContext(LinkerPathManager& paths, const std::string& projectName, const GameId game)
|
||||||
|
: m_paths(paths)
|
||||||
|
{
|
||||||
|
m_paths.m_asset_paths.LoadGameSpecific(projectName, game);
|
||||||
|
m_paths.m_gdt_paths.LoadGameSpecific(projectName, game);
|
||||||
|
m_paths.m_source_paths.LoadGameSpecific(projectName, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PathGameContext()
|
||||||
|
{
|
||||||
|
m_paths.m_asset_paths.UnloadGameSpecific();
|
||||||
|
m_paths.m_gdt_paths.UnloadGameSpecific();
|
||||||
|
m_paths.m_source_paths.UnloadGameSpecific();
|
||||||
|
}
|
||||||
|
|
||||||
|
PathGameContext(const PathGameContext& other) = delete;
|
||||||
|
PathGameContext(PathGameContext&& other) noexcept = delete;
|
||||||
|
PathGameContext& operator=(const PathGameContext& other) = delete;
|
||||||
|
PathGameContext& operator=(PathGameContext&& other) noexcept = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LinkerPathManager& m_paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LinkerImpl final : public Linker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LinkerImpl(LinkerArgs args)
|
||||||
|
: m_args(std::move(args))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Start() override
|
||||||
|
{
|
||||||
|
LinkerPathManager paths(m_args);
|
||||||
|
|
||||||
|
if (!LoadZones())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto result = true;
|
||||||
|
for (const auto& projectSpecifier : m_args.m_project_specifiers_to_build)
|
||||||
|
{
|
||||||
|
std::string projectName;
|
||||||
|
std::string targetName;
|
||||||
|
if (!GetProjectAndTargetFromProjectSpecifier(projectSpecifier, projectName, targetName))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BuildProject(paths, projectName, targetName))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnloadZones();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<ZoneDefinition> ReadZoneDefinition(LinkerPathManager& paths, const std::string& targetName, bool logMissing = true) const
|
||||||
|
{
|
||||||
|
auto& sourceSearchPath = paths.m_source_paths.GetSearchPaths();
|
||||||
|
std::unique_ptr<ZoneDefinition> zoneDefinition;
|
||||||
|
{
|
||||||
|
const auto definitionFileName = std::format("{}.zone", targetName);
|
||||||
|
const auto definitionStream = sourceSearchPath.Open(definitionFileName);
|
||||||
|
if (!definitionStream.IsOpen())
|
||||||
|
{
|
||||||
|
if (logMissing)
|
||||||
|
con::error("Could not find zone definition file for target \"{}\".", targetName);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneDefinitionInputStream zoneDefinitionInputStream(*definitionStream.m_stream, targetName, definitionFileName, sourceSearchPath);
|
||||||
|
zoneDefinition = zoneDefinitionInputStream.ReadDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zoneDefinition)
|
||||||
|
{
|
||||||
|
con::error("Failed to read zone definition file for target \"{}\".", targetName);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zoneDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadIgnoreEntries(LinkerPathManager& paths, const std::string& zoneName, const GameId game, AssetList& assetList) const
|
||||||
|
{
|
||||||
|
{
|
||||||
|
AssetListReader assetListReader(paths.m_source_paths.GetSearchPaths(), game);
|
||||||
|
const auto maybeReadAssetList = assetListReader.ReadAssetList(zoneName, false);
|
||||||
|
if (maybeReadAssetList)
|
||||||
|
{
|
||||||
|
assetList.m_entries.reserve(assetList.m_entries.size() + maybeReadAssetList->m_entries.size());
|
||||||
|
for (auto& entry : maybeReadAssetList->m_entries)
|
||||||
|
assetList.m_entries.emplace_back(std::move(entry));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto zoneDefinition = ReadZoneDefinition(paths, zoneName, false);
|
||||||
|
|
||||||
|
if (zoneDefinition)
|
||||||
|
{
|
||||||
|
assetList.m_entries.reserve(assetList.m_entries.size() + zoneDefinition->m_assets.size());
|
||||||
|
for (const auto& entry : zoneDefinition->m_assets)
|
||||||
|
assetList.m_entries.emplace_back(entry.m_asset_type, entry.m_asset_name, entry.m_is_reference);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessZoneDefinitionIgnores(LinkerPathManager& paths, const std::string& targetName, ZoneCreationContext& context) const
|
||||||
|
{
|
||||||
|
if (context.m_definition->m_ignores.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (const auto& ignore : context.m_definition->m_ignores)
|
||||||
|
{
|
||||||
|
if (ignore == targetName)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ReadIgnoreEntries(paths, ignore, context.m_definition->m_game, context.m_ignored_assets))
|
||||||
|
{
|
||||||
|
con::error("Failed to read asset listing for ignoring assets of project \"{}\".", ignore);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool LoadGdtFilesFromZoneDefinition(std::vector<std::unique_ptr<Gdt>>& gdtList, const ZoneDefinition& zoneDefinition, ISearchPath* gdtSearchPath)
|
||||||
|
{
|
||||||
|
for (const auto& gdtName : zoneDefinition.m_gdts)
|
||||||
|
{
|
||||||
|
const auto gdtFile = gdtSearchPath->Open(std::format("{}.gdt", gdtName));
|
||||||
|
if (!gdtFile.IsOpen())
|
||||||
|
{
|
||||||
|
con::error("Failed to open file for gdt \"{}\"", gdtName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GdtReader gdtReader(*gdtFile.m_stream);
|
||||||
|
auto gdt = std::make_unique<Gdt>();
|
||||||
|
if (!gdtReader.Read(*gdt))
|
||||||
|
{
|
||||||
|
con::error("Failed to read gdt file \"{}\"", gdtName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdtList.emplace_back(std::move(gdt));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Zone> CreateZoneForDefinition(
|
||||||
|
LinkerPathManager& paths, const fs::path& outDir, const fs::path& cacheDir, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
||||||
|
{
|
||||||
|
ZoneCreationContext context(&zoneDefinition, &paths.m_asset_paths.GetSearchPaths(), outDir, cacheDir);
|
||||||
|
if (!ProcessZoneDefinitionIgnores(paths, targetName, context))
|
||||||
|
return nullptr;
|
||||||
|
if (!LoadGdtFilesFromZoneDefinition(context.m_gdt_files, zoneDefinition, &paths.m_gdt_paths.GetSearchPaths()))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return zone_creator::CreateZoneForDefinition(zoneDefinition.m_game, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool WriteZoneToFile(IOutputPath& outPath, const Zone& zone)
|
||||||
|
{
|
||||||
|
const auto stream = outPath.Open(std::format("{}.ff", zone.m_name));
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
con::error("Failed to open file for zone: {}", zone.m_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
con::info("Building zone \"{}\"", zone.m_name);
|
||||||
|
|
||||||
|
if (!ZoneWriting::WriteZone(*stream, zone))
|
||||||
|
{
|
||||||
|
con::error("Writing zone failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
con::info("Created zone \"{}\"", zone.m_name);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildFastFile(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName, ZoneDefinition& zoneDefinition) const
|
||||||
|
{
|
||||||
|
const fs::path outDir(paths.m_linker_paths->BuildOutputFolderPath(projectName, zoneDefinition.m_game));
|
||||||
|
|
||||||
|
OutputPathFilesystem outputPath(outDir);
|
||||||
|
|
||||||
|
const fs::path cacheDir(paths.m_linker_paths->BuildCacheFolderPath(projectName, zoneDefinition.m_game));
|
||||||
|
SoundBankWriter::OutputPath = outDir;
|
||||||
|
|
||||||
|
const auto zone = CreateZoneForDefinition(paths, outDir, cacheDir, targetName, zoneDefinition);
|
||||||
|
auto result = zone != nullptr;
|
||||||
|
if (zone)
|
||||||
|
result = WriteZoneToFile(outputPath, *zone);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildProject(LinkerPathManager& paths, const std::string& projectName, const std::string& targetName) const
|
||||||
|
{
|
||||||
|
std::deque<std::string> targetsToBuild;
|
||||||
|
std::unordered_set<std::string> alreadyBuiltTargets;
|
||||||
|
|
||||||
|
targetsToBuild.emplace_back(targetName);
|
||||||
|
|
||||||
|
while (!targetsToBuild.empty())
|
||||||
|
{
|
||||||
|
const auto currentTarget = std::move(targetsToBuild.front());
|
||||||
|
targetsToBuild.pop_front();
|
||||||
|
alreadyBuiltTargets.emplace(currentTarget);
|
||||||
|
|
||||||
|
PathProjectContext projectContext(paths, projectName);
|
||||||
|
|
||||||
|
const auto zoneDefinition = ReadZoneDefinition(paths, targetName);
|
||||||
|
if (!zoneDefinition)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PathGameContext gameContext(paths, projectName, zoneDefinition->m_game);
|
||||||
|
|
||||||
|
if (!zoneDefinition->m_assets.empty())
|
||||||
|
{
|
||||||
|
if (!BuildFastFile(paths, projectName, targetName, *zoneDefinition))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto& referencedTarget : zoneDefinition->m_targets_to_build)
|
||||||
|
{
|
||||||
|
if (alreadyBuiltTargets.find(referencedTarget) == alreadyBuiltTargets.end())
|
||||||
|
{
|
||||||
|
targetsToBuild.emplace_back(referencedTarget);
|
||||||
|
con::info("Building referenced target \"{}\"", referencedTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadZones()
|
||||||
|
{
|
||||||
|
for (const auto& zonePath : m_args.m_zones_to_load)
|
||||||
|
{
|
||||||
|
if (!fs::is_regular_file(zonePath))
|
||||||
|
{
|
||||||
|
con::error("Could not find zone file to load \"{}\".", zonePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto zoneDirectory = fs::path(zonePath).remove_filename();
|
||||||
|
if (zoneDirectory.empty())
|
||||||
|
zoneDirectory = fs::current_path();
|
||||||
|
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
||||||
|
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
|
if (!maybeZone)
|
||||||
|
{
|
||||||
|
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
|
||||||
|
con::debug("Loaded zone \"{}\"", zone->m_name);
|
||||||
|
|
||||||
|
m_loaded_zones.emplace_back(std::move(zone));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnloadZones()
|
||||||
|
{
|
||||||
|
for (auto i = m_loaded_zones.rbegin(); i != m_loaded_zones.rend(); ++i)
|
||||||
|
{
|
||||||
|
auto& loadedZone = *i;
|
||||||
|
std::string zoneName = loadedZone->m_name;
|
||||||
|
|
||||||
|
loadedZone.reset();
|
||||||
|
|
||||||
|
con::debug("Unloaded zone \"{}\"", zoneName);
|
||||||
|
}
|
||||||
|
m_loaded_zones.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool GetProjectAndTargetFromProjectSpecifier(const std::string& projectSpecifier, std::string& projectName, std::string& targetName)
|
||||||
|
{
|
||||||
|
const auto targetNameSeparatorIndex = projectSpecifier.find_first_of('/');
|
||||||
|
if (targetNameSeparatorIndex == std::string::npos)
|
||||||
|
{
|
||||||
|
projectName = projectSpecifier;
|
||||||
|
targetName = projectSpecifier;
|
||||||
|
}
|
||||||
|
else if (projectSpecifier.find_first_of('/', targetNameSeparatorIndex + 1) != std::string::npos)
|
||||||
|
{
|
||||||
|
con::error("Project specifier cannot have more than one target name: \"{}\"", projectSpecifier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
projectName = projectSpecifier.substr(0, targetNameSeparatorIndex);
|
||||||
|
targetName = projectSpecifier.substr(targetNameSeparatorIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectName.empty())
|
||||||
|
{
|
||||||
|
con::error("Project name cannot be empty: \"{}\"", projectSpecifier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetName.empty())
|
||||||
|
{
|
||||||
|
con::error("Target name cannot be empty: \"{}\"", projectSpecifier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkerArgs m_args;
|
||||||
|
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<Linker> Linker::Create(LinkerArgs args)
|
||||||
|
{
|
||||||
|
return std::make_unique<LinkerImpl>(std::move(args));
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "LinkerArgs.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Linker
|
class Linker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Linker() = default;
|
|
||||||
virtual ~Linker() = default;
|
virtual ~Linker() = default;
|
||||||
|
|
||||||
Linker(const Linker& other) = delete;
|
static std::unique_ptr<Linker> Create(LinkerArgs args);
|
||||||
Linker(Linker&& other) noexcept = delete;
|
|
||||||
Linker& operator=(const Linker& other) = delete;
|
|
||||||
Linker& operator=(Linker&& other) noexcept = delete;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Starts the Linker application logic.
|
* \brief Starts the Linker application logic.
|
||||||
@@ -18,7 +17,5 @@ public:
|
|||||||
* \param argv The command line arguments.
|
* \param argv The command line arguments.
|
||||||
* \return \c true if the application was successful or \c false if an error occurred.
|
* \return \c true if the application was successful or \c false if an error occurred.
|
||||||
*/
|
*/
|
||||||
virtual bool Start(int argc, const char** argv) = 0;
|
virtual bool Start() = 0;
|
||||||
|
|
||||||
static std::unique_ptr<Linker> Create();
|
|
||||||
};
|
};
|
||||||
@@ -104,7 +104,7 @@ XAssetInfoGeneric* AssetCreationContext::LoadDefaultAssetDependency(const asset_
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_t assetType, const std::string& assetName)
|
XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_t assetType, const std::string& assetName, bool required)
|
||||||
{
|
{
|
||||||
auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName);
|
||||||
if (alreadyLoadedAsset)
|
if (alreadyLoadedAsset)
|
||||||
@@ -131,7 +131,7 @@ XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_
|
|||||||
|
|
||||||
con::error("Could not load asset \"{}\" of type \"{}\"", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
con::error("Could not load asset \"{}\" of type \"{}\"", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
||||||
}
|
}
|
||||||
else
|
else if (required)
|
||||||
{
|
{
|
||||||
con::error("Missing asset \"{}\" of type \"{}\"", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
con::error("Missing asset \"{}\" of type \"{}\"", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public:
|
|||||||
return static_cast<XAssetInfo<typename AssetType::Type>*>(LoadDependencyGeneric(AssetType::EnumEntry, assetName));
|
return static_cast<XAssetInfo<typename AssetType::Type>*>(LoadDependencyGeneric(AssetType::EnumEntry, assetName));
|
||||||
}
|
}
|
||||||
|
|
||||||
XAssetInfoGeneric* LoadDependencyGeneric(asset_type_t assetType, const std::string& assetName);
|
XAssetInfoGeneric* LoadDependencyGeneric(asset_type_t assetType, const std::string& assetName, bool required = true);
|
||||||
|
|
||||||
template<typename AssetType> IndirectAssetReference LoadIndirectAssetReference(const std::string& assetName)
|
template<typename AssetType> IndirectAssetReference LoadIndirectAssetReference(const std::string& assetName)
|
||||||
{
|
{
|
||||||
|
|||||||
61
src/ObjLoading/Asset/GlobalAssetPoolsLoader.cpp
Normal file
61
src/ObjLoading/Asset/GlobalAssetPoolsLoader.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#include "GlobalAssetPoolsLoader.h"
|
||||||
|
|
||||||
|
GlobalAssetPoolsRegistrationPreparation::GlobalAssetPoolsRegistrationPreparation(GenericAssetRegistration& registration,
|
||||||
|
Zone& zone,
|
||||||
|
Zone& foreignZone,
|
||||||
|
AssetCreationContext& context)
|
||||||
|
: m_registration(registration),
|
||||||
|
m_zone(zone),
|
||||||
|
m_foreign_zone(foreignZone),
|
||||||
|
m_context(context),
|
||||||
|
m_failure(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<XAssetInfoGeneric*> GlobalAssetPoolsRegistrationPreparation::Visit_Dependency(const asset_type_t assetType, const char* assetName)
|
||||||
|
{
|
||||||
|
if (assetName && assetName[0] == ',')
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Try to load the actual asset when the asset from the global asset pools just references one.
|
||||||
|
If that fails, keep the reference to not destroy previous existing behaviour of just being able to use assets from the global pools
|
||||||
|
without ignores.
|
||||||
|
*/
|
||||||
|
auto* nonReferenceAssetName = &assetName[1];
|
||||||
|
|
||||||
|
auto* assetDependency = m_context.LoadDependencyGeneric(assetType, nonReferenceAssetName, false);
|
||||||
|
if (assetDependency)
|
||||||
|
{
|
||||||
|
m_registration.AddDependency(assetDependency);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* newDependency = m_context.LoadDependencyGeneric(assetType, assetName);
|
||||||
|
if (newDependency)
|
||||||
|
{
|
||||||
|
m_registration.AddDependency(newDependency);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_failure = true;
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<scr_string_t> GlobalAssetPoolsRegistrationPreparation::Visit_ScriptString(scr_string_t scriptString)
|
||||||
|
{
|
||||||
|
// Make sure any used script string is available in the created zone
|
||||||
|
m_zone.m_script_strings.AddOrGetScriptString(m_foreign_zone.m_script_strings.CValue(scriptString));
|
||||||
|
m_registration.AddScriptString(scriptString);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAssetPoolsRegistrationPreparation::Visit_IndirectAssetRef(const asset_type_t assetType, const char* assetName)
|
||||||
|
{
|
||||||
|
m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReferenceGeneric(assetType, assetName));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalAssetPoolsRegistrationPreparation::Failed() const
|
||||||
|
{
|
||||||
|
return m_failure;
|
||||||
|
}
|
||||||
@@ -1,13 +1,36 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Asset/IAssetCreator.h"
|
#include "Asset/IAssetCreator.h"
|
||||||
|
#include "Marking/AssetVisitor.h"
|
||||||
|
#include "Marking/BaseAssetMarker.h"
|
||||||
#include "Pool/GlobalAssetPool.h"
|
#include "Pool/GlobalAssetPool.h"
|
||||||
|
|
||||||
|
class GlobalAssetPoolsRegistrationPreparation : public AssetVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GlobalAssetPoolsRegistrationPreparation(GenericAssetRegistration& registration, Zone& zone, Zone& foreignZone, AssetCreationContext& context);
|
||||||
|
|
||||||
|
std::optional<XAssetInfoGeneric*> Visit_Dependency(asset_type_t assetType, const char* assetName) override;
|
||||||
|
std::optional<scr_string_t> Visit_ScriptString(scr_string_t scriptString) override;
|
||||||
|
void Visit_IndirectAssetRef(asset_type_t assetType, const char* assetName) override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool Failed() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GenericAssetRegistration& m_registration;
|
||||||
|
Zone& m_zone;
|
||||||
|
Zone& m_foreign_zone;
|
||||||
|
AssetCreationContext& m_context;
|
||||||
|
|
||||||
|
bool m_failure;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename AssetType> class GlobalAssetPoolsLoader : public AssetCreator<AssetType>
|
template<typename AssetType> class GlobalAssetPoolsLoader : public AssetCreator<AssetType>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
|
|
||||||
GlobalAssetPoolsLoader(Zone& zone)
|
explicit GlobalAssetPoolsLoader(Zone& zone)
|
||||||
: m_zone(zone)
|
: m_zone(zone)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -21,26 +44,12 @@ public:
|
|||||||
|
|
||||||
AssetRegistration<AssetType> registration(assetName, existingAsset->Asset());
|
AssetRegistration<AssetType> registration(assetName, existingAsset->Asset());
|
||||||
|
|
||||||
for (const auto* dependency : existingAsset->m_dependencies)
|
GlobalAssetPoolsRegistrationPreparation registrationPreparation(registration, m_zone, *existingAsset->m_zone, context);
|
||||||
{
|
AssetMarker<AssetType> marker(registrationPreparation);
|
||||||
auto* newDependency = context.LoadDependencyGeneric(dependency->m_type, dependency->m_name);
|
marker.Mark(existingAsset->Asset());
|
||||||
if (newDependency)
|
|
||||||
registration.AddDependency(newDependency);
|
|
||||||
else
|
|
||||||
return AssetCreationResult::Failure();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& indirectAssetReference : existingAsset->m_indirect_asset_references)
|
|
||||||
registration.AddIndirectAssetReference(context.LoadIndirectAssetReferenceGeneric(indirectAssetReference.m_type, indirectAssetReference.m_name));
|
|
||||||
|
|
||||||
// Make sure any used script string is available in the created zone
|
|
||||||
// The replacement of the scr_string_t values will be done upon writing
|
|
||||||
for (const auto scrString : existingAsset->m_used_script_strings)
|
|
||||||
m_zone.m_script_strings.AddOrGetScriptString(existingAsset->m_zone->m_script_strings.CValue(scrString));
|
|
||||||
|
|
||||||
auto* newAsset = context.AddAsset(std::move(registration));
|
auto* newAsset = context.AddAsset(std::move(registration));
|
||||||
|
// Make sure we remember this asset came from a different zone
|
||||||
// Make sure we remember this asset came from another zone
|
|
||||||
newAsset->m_zone = existingAsset->m_zone;
|
newAsset->m_zone = existingAsset->m_zone;
|
||||||
|
|
||||||
return AssetCreationResult::Success(newAsset);
|
return AssetCreationResult::Success(newAsset);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public:
|
|||||||
AssetCreationResult CreateDefaultAsset(const std::string& assetName, AssetCreationContext& context) const override
|
AssetCreationResult CreateDefaultAsset(const std::string& assetName, AssetCreationContext& context) const override
|
||||||
{
|
{
|
||||||
auto* asset = m_memory.Alloc<typename AssetType::Type>();
|
auto* asset = m_memory.Alloc<typename AssetType::Type>();
|
||||||
AssetNameAccessor<AssetType>{}(*asset) = m_memory.Dup(assetName.c_str());
|
AssetName<AssetType>(*asset) = m_memory.Dup(assetName.c_str());
|
||||||
|
|
||||||
return AssetCreationResult::Success(context.AddAsset<AssetType>(assetName, asset));
|
return AssetCreationResult::Success(context.AddAsset<AssetType>(assetName, asset));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "ObjLoaderIW3.h"
|
#include "ObjLoaderIW3.h"
|
||||||
|
|
||||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||||
|
#include "Game/IW3/AssetMarkerIW3.h"
|
||||||
#include "Game/IW3/GameIW3.h"
|
#include "Game/IW3/GameIW3.h"
|
||||||
#include "Game/IW3/IW3.h"
|
#include "Game/IW3/IW3.h"
|
||||||
#include "Game/IW3/XModel/LoaderXModelIW3.h"
|
#include "Game/IW3/XModel/LoaderXModelIW3.h"
|
||||||
@@ -65,7 +66,7 @@ namespace
|
|||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSound>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSound>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundCurve>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundCurve>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetLoadedSound>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetLoadedSound>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMap>>(zone));
|
// collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMap>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapPvs>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapPvs>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
||||||
@@ -78,7 +79,7 @@ namespace
|
|||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetMenu>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetMenu>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetLocalize>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetLocalize>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetWeapon>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetWeapon>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundDriverGlobals>>(zone));
|
// collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundDriverGlobals>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetFx>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetFx>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetImpactFx>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetImpactFx>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetRawFile>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetRawFile>>(zone));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "ObjLoaderIW4.h"
|
#include "ObjLoaderIW4.h"
|
||||||
|
|
||||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||||
|
#include "Game/IW4/AssetMarkerIW4.h"
|
||||||
#include "Game/IW4/GameIW4.h"
|
#include "Game/IW4/GameIW4.h"
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
#include "Game/IW4/XModel/LoaderXModelIW4.h"
|
#include "Game/IW4/XModel/LoaderXModelIW4.h"
|
||||||
@@ -79,7 +80,7 @@ namespace
|
|||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetPhysPreset>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetPhysPreset>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetPhysCollMap>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetPhysCollMap>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetXAnim>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetXAnim>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetXModelSurfs>>(zone));
|
// collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetXModelSurfs>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetXModel>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetXModel>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetMaterial>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetMaterial>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetPixelShader>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetPixelShader>>(zone));
|
||||||
@@ -90,7 +91,7 @@ namespace
|
|||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSound>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSound>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundCurve>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundCurve>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetLoadedSound>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetLoadedSound>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapSp>>(zone));
|
// collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapSp>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapMp>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapMp>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "ObjLoaderIW5.h"
|
#include "ObjLoaderIW5.h"
|
||||||
|
|
||||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||||
|
#include "Game/IW5/AssetMarkerIW5.h"
|
||||||
#include "Game/IW5/GameIW5.h"
|
#include "Game/IW5/GameIW5.h"
|
||||||
#include "Game/IW5/IW5.h"
|
#include "Game/IW5/IW5.h"
|
||||||
#include "Game/IW5/XModel/LoaderXModelIW5.h"
|
#include "Game/IW5/XModel/LoaderXModelIW5.h"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "ObjLoaderT5.h"
|
#include "ObjLoaderT5.h"
|
||||||
|
|
||||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||||
|
#include "Game/T5/AssetMarkerT5.h"
|
||||||
#include "Game/T5/GameT5.h"
|
#include "Game/T5/GameT5.h"
|
||||||
#include "Game/T5/T5.h"
|
#include "Game/T5/T5.h"
|
||||||
#include "Game/T5/XModel/LoaderXModelT5.h"
|
#include "Game/T5/XModel/LoaderXModelT5.h"
|
||||||
@@ -71,7 +72,7 @@ namespace
|
|||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetImage>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetImage>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundBank>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundBank>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundPatch>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundPatch>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMap>>(zone));
|
// collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMap>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapPvs>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapPvs>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||||
#include "FontIcon/CsvLoaderFontIconT6.h"
|
#include "FontIcon/CsvLoaderFontIconT6.h"
|
||||||
#include "FontIcon/JsonLoaderFontIconT6.h"
|
#include "FontIcon/JsonLoaderFontIconT6.h"
|
||||||
|
#include "Game/T6/AssetMarkerT6.h"
|
||||||
#include "Game/T6/CommonT6.h"
|
#include "Game/T6/CommonT6.h"
|
||||||
#include "Game/T6/GameAssetPoolT6.h"
|
#include "Game/T6/GameAssetPoolT6.h"
|
||||||
#include "Game/T6/GameT6.h"
|
#include "Game/T6/GameT6.h"
|
||||||
@@ -340,7 +341,7 @@ namespace T6
|
|||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetImage>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetImage>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundBank>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundBank>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundPatch>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetSoundPatch>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMap>>(zone));
|
// collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMap>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapPvs>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetClipMapPvs>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetComWorld>>(zone));
|
||||||
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
collection.AddAssetCreator(std::make_unique<GlobalAssetPoolsLoader<AssetGameWorldSp>>(zone));
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
Unlinker = {}
|
|
||||||
|
|
||||||
function Unlinker:include(includes)
|
|
||||||
if includes:handle(self:name()) then
|
|
||||||
includedirs {
|
|
||||||
path.join(ProjectFolder(), "Unlinker")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Unlinker:link(links)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function Unlinker:use()
|
|
||||||
dependson(self:name())
|
|
||||||
end
|
|
||||||
|
|
||||||
function Unlinker:name()
|
|
||||||
return "Unlinker"
|
|
||||||
end
|
|
||||||
|
|
||||||
function Unlinker:project()
|
|
||||||
local folder = ProjectFolder()
|
|
||||||
local includes = Includes:create()
|
|
||||||
local links = Links:create()
|
|
||||||
|
|
||||||
project(self:name())
|
|
||||||
targetdir(TargetDirectoryBin)
|
|
||||||
location "%{wks.location}/src/%{prj.name}"
|
|
||||||
kind "ConsoleApp"
|
|
||||||
language "C++"
|
|
||||||
|
|
||||||
files {
|
|
||||||
path.join(folder, "Unlinker/**.h"),
|
|
||||||
path.join(folder, "Unlinker/**.cpp")
|
|
||||||
}
|
|
||||||
|
|
||||||
self:include(includes)
|
|
||||||
Utils:include(includes)
|
|
||||||
ZoneLoading:include(includes)
|
|
||||||
ObjLoading:include(includes)
|
|
||||||
ObjWriting:include(includes)
|
|
||||||
|
|
||||||
Raw:use()
|
|
||||||
|
|
||||||
links:linkto(Utils)
|
|
||||||
links:linkto(ZoneLoading)
|
|
||||||
links:linkto(ObjLoading)
|
|
||||||
links:linkto(ObjWriting)
|
|
||||||
links:linkall()
|
|
||||||
end
|
|
||||||
@@ -1,342 +0,0 @@
|
|||||||
#include "Unlinker.h"
|
|
||||||
|
|
||||||
#include "ContentLister/ContentPrinter.h"
|
|
||||||
#include "IObjLoader.h"
|
|
||||||
#include "IObjWriter.h"
|
|
||||||
#include "ObjWriting.h"
|
|
||||||
#include "SearchPath/IWD.h"
|
|
||||||
#include "SearchPath/OutputPathFilesystem.h"
|
|
||||||
#include "UnlinkerArgs.h"
|
|
||||||
#include "UnlinkerPaths.h"
|
|
||||||
#include "Utils/ClassUtils.h"
|
|
||||||
#include "Utils/Logging/Log.h"
|
|
||||||
#include "Utils/ObjFileStream.h"
|
|
||||||
#include "Zone/Definition/ZoneDefWriter.h"
|
|
||||||
#include "ZoneLoading.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <format>
|
|
||||||
#include <fstream>
|
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
class Unlinker::Impl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \copydoc Unlinker::Start
|
|
||||||
*/
|
|
||||||
bool Start(const int argc, const char** argv)
|
|
||||||
{
|
|
||||||
con::init();
|
|
||||||
|
|
||||||
auto shouldContinue = true;
|
|
||||||
if (!m_args.ParseArgs(argc, argv, shouldContinue))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!shouldContinue)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
UnlinkerPaths paths;
|
|
||||||
if (!paths.LoadUserPaths(m_args))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!LoadZones(paths))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto result = UnlinkZones(paths);
|
|
||||||
|
|
||||||
UnloadZones();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] bool ShouldLoadObj() const
|
|
||||||
{
|
|
||||||
return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST && !m_args.m_skip_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool WriteZoneDefinitionFile(const Zone& zone, const fs::path& zoneDefinitionFileFolder) const
|
|
||||||
{
|
|
||||||
auto zoneDefinitionFilePath(zoneDefinitionFileFolder);
|
|
||||||
zoneDefinitionFilePath.append(zone.m_name);
|
|
||||||
zoneDefinitionFilePath.replace_extension(".zone");
|
|
||||||
|
|
||||||
std::ofstream zoneDefinitionFile(zoneDefinitionFilePath, std::fstream::out | std::fstream::binary);
|
|
||||||
if (!zoneDefinitionFile.is_open())
|
|
||||||
{
|
|
||||||
con::error("Failed to open file for zone definition file of zone \"{}\".", zone.m_name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto* zoneDefWriter = IZoneDefWriter::GetZoneDefWriterForGame(zone.m_game_id);
|
|
||||||
zoneDefWriter->WriteZoneDef(zoneDefinitionFile, zone, m_args.m_use_gdt);
|
|
||||||
|
|
||||||
zoneDefinitionFile.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool OpenGdtFile(const Zone& zone, const fs::path& outputFolder, std::ofstream& stream)
|
|
||||||
{
|
|
||||||
auto gdtFilePath(outputFolder);
|
|
||||||
gdtFilePath.append("source_data");
|
|
||||||
|
|
||||||
fs::create_directories(gdtFilePath);
|
|
||||||
|
|
||||||
gdtFilePath.append(zone.m_name);
|
|
||||||
gdtFilePath.replace_extension(".gdt");
|
|
||||||
|
|
||||||
stream = std::ofstream(gdtFilePath, std::fstream::out | std::fstream::binary);
|
|
||||||
if (!stream.is_open())
|
|
||||||
{
|
|
||||||
con::error("Failed to open file for zone definition file of zone \"{}\".", zone.m_name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateAssetIncludesAndExcludes(const AssetDumpingContext& context) const
|
|
||||||
{
|
|
||||||
const auto assetTypeCount = context.m_zone.m_pools->GetAssetTypeCount();
|
|
||||||
|
|
||||||
ObjWriting::Configuration.AssetTypesToHandleBitfield = std::vector<bool>(assetTypeCount);
|
|
||||||
|
|
||||||
std::vector<bool> handledSpecifiedAssets(m_args.m_specified_asset_types.size());
|
|
||||||
for (auto i = 0u; i < assetTypeCount; i++)
|
|
||||||
{
|
|
||||||
const auto assetTypeName = std::string(*context.m_zone.m_pools->GetAssetTypeName(i));
|
|
||||||
|
|
||||||
const auto foundSpecifiedEntry = m_args.m_specified_asset_type_map.find(assetTypeName);
|
|
||||||
if (foundSpecifiedEntry != m_args.m_specified_asset_type_map.end())
|
|
||||||
{
|
|
||||||
ObjWriting::Configuration.AssetTypesToHandleBitfield[i] = m_args.m_asset_type_handling == UnlinkerArgs::AssetTypeHandling::INCLUDE;
|
|
||||||
assert(foundSpecifiedEntry->second < handledSpecifiedAssets.size());
|
|
||||||
handledSpecifiedAssets[foundSpecifiedEntry->second] = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ObjWriting::Configuration.AssetTypesToHandleBitfield[i] = m_args.m_asset_type_handling == UnlinkerArgs::AssetTypeHandling::EXCLUDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto anySpecifiedValueInvalid = false;
|
|
||||||
for (auto i = 0u; i < handledSpecifiedAssets.size(); i++)
|
|
||||||
{
|
|
||||||
if (!handledSpecifiedAssets[i])
|
|
||||||
{
|
|
||||||
con::error("Unknown asset type \"{}\"", m_args.m_specified_asset_types[i]);
|
|
||||||
anySpecifiedValueInvalid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anySpecifiedValueInvalid)
|
|
||||||
{
|
|
||||||
con::error("Valid asset types are:");
|
|
||||||
|
|
||||||
auto first = true;
|
|
||||||
std::ostringstream ss;
|
|
||||||
for (auto i = 0u; i < assetTypeCount; i++)
|
|
||||||
{
|
|
||||||
const auto assetTypeName = std::string(*context.m_zone.m_pools->GetAssetTypeName(i));
|
|
||||||
|
|
||||||
if (first)
|
|
||||||
first = false;
|
|
||||||
else
|
|
||||||
ss << ", ";
|
|
||||||
ss << assetTypeName;
|
|
||||||
}
|
|
||||||
con::error(ss.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Performs the tasks specified by the command line arguments on the specified zone.
|
|
||||||
* \param searchPath The search path for obj data.
|
|
||||||
* \param zone The zone to handle.
|
|
||||||
* \return \c true if handling the zone was successful, otherwise \c false
|
|
||||||
*/
|
|
||||||
bool HandleZone(ISearchPath& searchPath, Zone& zone) const
|
|
||||||
{
|
|
||||||
if (m_args.m_task == UnlinkerArgs::ProcessingTask::LIST)
|
|
||||||
{
|
|
||||||
const ContentPrinter printer(zone);
|
|
||||||
printer.PrintContent();
|
|
||||||
}
|
|
||||||
else if (m_args.m_task == UnlinkerArgs::ProcessingTask::DUMP)
|
|
||||||
{
|
|
||||||
const auto outputFolderPathStr = m_args.GetOutputFolderPathForZone(zone);
|
|
||||||
const fs::path outputFolderPath(outputFolderPathStr);
|
|
||||||
fs::create_directories(outputFolderPath);
|
|
||||||
|
|
||||||
fs::path zoneDefinitionFileFolder(outputFolderPath);
|
|
||||||
zoneDefinitionFileFolder.append("zone_source");
|
|
||||||
fs::create_directories(zoneDefinitionFileFolder);
|
|
||||||
|
|
||||||
if (!WriteZoneDefinitionFile(zone, zoneDefinitionFileFolder))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
OutputPathFilesystem outputFolderOutputPath(outputFolderPath);
|
|
||||||
AssetDumpingContext context(zone, outputFolderPathStr, outputFolderOutputPath, searchPath, std::nullopt);
|
|
||||||
|
|
||||||
std::ofstream gdtStream;
|
|
||||||
if (m_args.m_use_gdt)
|
|
||||||
{
|
|
||||||
if (!OpenGdtFile(zone, outputFolderPath, gdtStream))
|
|
||||||
return false;
|
|
||||||
auto gdt = std::make_unique<GdtOutputStream>(gdtStream);
|
|
||||||
gdt->BeginStream();
|
|
||||||
|
|
||||||
const auto* game = IGame::GetGameById(zone.m_game_id);
|
|
||||||
gdt->WriteVersion(GdtVersion(game->GetShortName(), 1));
|
|
||||||
|
|
||||||
context.m_gdt = std::move(gdt);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateAssetIncludesAndExcludes(context);
|
|
||||||
|
|
||||||
const auto* objWriter = IObjWriter::GetObjWriterForGame(zone.m_game_id);
|
|
||||||
|
|
||||||
auto result = objWriter->DumpZone(context);
|
|
||||||
|
|
||||||
if (m_args.m_use_gdt)
|
|
||||||
{
|
|
||||||
context.m_gdt->EndStream();
|
|
||||||
gdtStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
con::error("Dumping zone failed!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoadZones(UnlinkerPaths& paths)
|
|
||||||
{
|
|
||||||
for (const auto& zonePath : m_args.m_zones_to_load)
|
|
||||||
{
|
|
||||||
if (!fs::is_regular_file(zonePath))
|
|
||||||
{
|
|
||||||
con::error("Could not find file \"{}\".", zonePath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
|
|
||||||
|
|
||||||
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
|
||||||
if (!maybeZone)
|
|
||||||
{
|
|
||||||
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto zone = std::move(*maybeZone);
|
|
||||||
|
|
||||||
con::debug("Loaded zone \"{}\"", zone->m_name);
|
|
||||||
|
|
||||||
if (ShouldLoadObj())
|
|
||||||
{
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
|
||||||
objLoader->LoadReferencedContainersForZone(*searchPathsForZone, *zone);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_loaded_zones.emplace_back(std::move(zone));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadZones()
|
|
||||||
{
|
|
||||||
for (auto i = m_loaded_zones.rbegin(); i != m_loaded_zones.rend(); ++i)
|
|
||||||
{
|
|
||||||
auto& loadedZone = *i;
|
|
||||||
|
|
||||||
// Copy zone name since we deallocate before logging
|
|
||||||
const auto zoneName = loadedZone->m_name;
|
|
||||||
|
|
||||||
if (ShouldLoadObj())
|
|
||||||
{
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(loadedZone->m_game_id);
|
|
||||||
objLoader->UnloadContainersOfZone(*loadedZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedZone.reset();
|
|
||||||
|
|
||||||
con::debug("Unloaded zone \"{}\"", zoneName);
|
|
||||||
}
|
|
||||||
m_loaded_zones.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UnlinkZones(UnlinkerPaths& paths) const
|
|
||||||
{
|
|
||||||
for (const auto& zonePath : m_args.m_zones_to_unlink)
|
|
||||||
{
|
|
||||||
if (!fs::is_regular_file(zonePath))
|
|
||||||
{
|
|
||||||
con::error("Could not find file \"{}\".", zonePath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto zoneDirectory = fs::path(zonePath).remove_filename();
|
|
||||||
if (zoneDirectory.empty())
|
|
||||||
zoneDirectory = fs::current_path();
|
|
||||||
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
|
||||||
|
|
||||||
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
|
||||||
|
|
||||||
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
|
||||||
if (!maybeZone)
|
|
||||||
{
|
|
||||||
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto zone = std::move(*maybeZone);
|
|
||||||
|
|
||||||
con::debug("Loaded zone \"{}\"", zone->m_name);
|
|
||||||
|
|
||||||
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
|
||||||
if (ShouldLoadObj())
|
|
||||||
objLoader->LoadReferencedContainersForZone(*searchPathsForZone, *zone);
|
|
||||||
|
|
||||||
if (!HandleZone(*searchPathsForZone, *zone))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (ShouldLoadObj())
|
|
||||||
objLoader->UnloadContainersOfZone(*zone);
|
|
||||||
|
|
||||||
// Copy zone name for using it after freeing the zone
|
|
||||||
std::string zoneName = zone->m_name;
|
|
||||||
zone.reset();
|
|
||||||
con::debug("Unloaded zone \"{}\"", zoneName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnlinkerArgs m_args;
|
|
||||||
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
|
|
||||||
};
|
|
||||||
|
|
||||||
Unlinker::Unlinker()
|
|
||||||
{
|
|
||||||
m_impl = new Impl();
|
|
||||||
}
|
|
||||||
|
|
||||||
Unlinker::~Unlinker()
|
|
||||||
{
|
|
||||||
delete m_impl;
|
|
||||||
m_impl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Unlinker::Start(const int argc, const char** argv) const
|
|
||||||
{
|
|
||||||
return m_impl->Start(argc, argv);
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class Unlinker
|
|
||||||
{
|
|
||||||
class Impl;
|
|
||||||
Impl* m_impl;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Unlinker();
|
|
||||||
~Unlinker();
|
|
||||||
|
|
||||||
Unlinker(const Unlinker& other) = delete;
|
|
||||||
Unlinker(Unlinker&& other) noexcept = delete;
|
|
||||||
Unlinker& operator=(const Unlinker& other) = delete;
|
|
||||||
Unlinker& operator=(Unlinker&& other) noexcept = delete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Starts the Unlinker application logic.
|
|
||||||
* \param argc The amount of command line arguments specified.
|
|
||||||
* \param argv The command line arguments.
|
|
||||||
* \return \c true if the application was successful or \c false if an error occurred.
|
|
||||||
*/
|
|
||||||
bool Start(int argc, const char** argv) const;
|
|
||||||
};
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include "Unlinker.h"
|
|
||||||
|
|
||||||
int main(const int argc, const char** argv)
|
|
||||||
{
|
|
||||||
Unlinker unlinker;
|
|
||||||
|
|
||||||
return unlinker.Start(argc, argv) ? 0 : 1;
|
|
||||||
}
|
|
||||||
49
src/UnlinkerCli.lua
Normal file
49
src/UnlinkerCli.lua
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
UnlinkerCli = {}
|
||||||
|
|
||||||
|
function UnlinkerCli:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
includedirs {
|
||||||
|
path.join(ProjectFolder(), "UnlinkerCli")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function UnlinkerCli:link(links)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function UnlinkerCli:use()
|
||||||
|
dependson(self:name())
|
||||||
|
end
|
||||||
|
|
||||||
|
function UnlinkerCli:name()
|
||||||
|
return "UnlinkerCli"
|
||||||
|
end
|
||||||
|
|
||||||
|
function UnlinkerCli:project()
|
||||||
|
local folder = ProjectFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
local links = Links:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryBin)
|
||||||
|
targetname "Unlinker"
|
||||||
|
location "%{wks.location}/src/%{prj.name}"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "UnlinkerCli/**.h"),
|
||||||
|
path.join(folder, "UnlinkerCli/**.cpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
Unlinking:include(includes)
|
||||||
|
|
||||||
|
Raw:use()
|
||||||
|
|
||||||
|
links:linkto(Utils)
|
||||||
|
links:linkto(Unlinking)
|
||||||
|
links:linkall()
|
||||||
|
end
|
||||||
19
src/UnlinkerCli/main.cpp
Normal file
19
src/UnlinkerCli/main.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "Unlinker.h"
|
||||||
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
|
int main(const int argc, const char** argv)
|
||||||
|
{
|
||||||
|
con::init();
|
||||||
|
|
||||||
|
UnlinkerArgs args;
|
||||||
|
auto shouldContinue = true;
|
||||||
|
if (!args.ParseArgs(argc, argv, shouldContinue))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!shouldContinue)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const auto unlinker = Unlinker::Create(std::move(args));
|
||||||
|
|
||||||
|
return unlinker->Start() ? 0 : 1;
|
||||||
|
}
|
||||||
57
src/Unlinking.lua
Normal file
57
src/Unlinking.lua
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
Unlinking = {}
|
||||||
|
|
||||||
|
function Unlinking:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
ZoneCommon:include(includes)
|
||||||
|
includedirs {
|
||||||
|
path.join(ProjectFolder(), "Unlinking"),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Unlinking:link(links)
|
||||||
|
links:add(self:name())
|
||||||
|
links:linkto(Utils)
|
||||||
|
links:linkto(ZoneLoading)
|
||||||
|
links:linkto(ObjLoading)
|
||||||
|
links:linkto(ObjWriting)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Unlinking:use()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function Unlinking:name()
|
||||||
|
return "Unlinking"
|
||||||
|
end
|
||||||
|
|
||||||
|
function Unlinking:project()
|
||||||
|
local folder = ProjectFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryLib)
|
||||||
|
location "%{wks.location}/src/%{prj.name}"
|
||||||
|
kind "StaticLib"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "Unlinking/**.h"),
|
||||||
|
path.join(folder, "Unlinking/**.cpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
vpaths {
|
||||||
|
["*"] = {
|
||||||
|
path.join(folder, "Unlinking")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCommon:use()
|
||||||
|
useSourceTemplating("Unlinking")
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
ZoneLoading:include(includes)
|
||||||
|
ObjLoading:include(includes)
|
||||||
|
ObjWriting:include(includes)
|
||||||
|
end
|
||||||
327
src/Unlinking/Unlinker.cpp
Normal file
327
src/Unlinking/Unlinker.cpp
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
#include "Unlinker.h"
|
||||||
|
|
||||||
|
#include "ContentLister/ContentPrinter.h"
|
||||||
|
#include "IObjLoader.h"
|
||||||
|
#include "IObjWriter.h"
|
||||||
|
#include "ObjWriting.h"
|
||||||
|
#include "SearchPath/IWD.h"
|
||||||
|
#include "SearchPath/OutputPathFilesystem.h"
|
||||||
|
#include "UnlinkerArgs.h"
|
||||||
|
#include "UnlinkerPaths.h"
|
||||||
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "Utils/Logging/Log.h"
|
||||||
|
#include "Utils/ObjFileStream.h"
|
||||||
|
#include "Zone/Definition/ZoneDefWriter.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <fstream>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class UnlinkerImpl : public Unlinker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnlinkerImpl(UnlinkerArgs args)
|
||||||
|
: m_args(std::move(args))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Start() override
|
||||||
|
{
|
||||||
|
UnlinkerPaths paths;
|
||||||
|
if (!paths.LoadUserPaths(m_args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!LoadZones(paths))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto result = UnlinkZones(paths);
|
||||||
|
|
||||||
|
UnloadZones();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] bool ShouldLoadObj() const
|
||||||
|
{
|
||||||
|
return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST && !m_args.m_skip_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool WriteZoneDefinitionFile(const Zone& zone, const fs::path& zoneDefinitionFileFolder) const
|
||||||
|
{
|
||||||
|
auto zoneDefinitionFilePath(zoneDefinitionFileFolder);
|
||||||
|
zoneDefinitionFilePath.append(zone.m_name);
|
||||||
|
zoneDefinitionFilePath.replace_extension(".zone");
|
||||||
|
|
||||||
|
std::ofstream zoneDefinitionFile(zoneDefinitionFilePath, std::fstream::out | std::fstream::binary);
|
||||||
|
if (!zoneDefinitionFile.is_open())
|
||||||
|
{
|
||||||
|
con::error("Failed to open file for zone definition file of zone \"{}\".", zone.m_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* zoneDefWriter = IZoneDefWriter::GetZoneDefWriterForGame(zone.m_game_id);
|
||||||
|
zoneDefWriter->WriteZoneDef(zoneDefinitionFile, zone, m_args.m_use_gdt);
|
||||||
|
|
||||||
|
zoneDefinitionFile.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool OpenGdtFile(const Zone& zone, const fs::path& outputFolder, std::ofstream& stream)
|
||||||
|
{
|
||||||
|
auto gdtFilePath(outputFolder);
|
||||||
|
gdtFilePath.append("source_data");
|
||||||
|
|
||||||
|
fs::create_directories(gdtFilePath);
|
||||||
|
|
||||||
|
gdtFilePath.append(zone.m_name);
|
||||||
|
gdtFilePath.replace_extension(".gdt");
|
||||||
|
|
||||||
|
stream = std::ofstream(gdtFilePath, std::fstream::out | std::fstream::binary);
|
||||||
|
if (!stream.is_open())
|
||||||
|
{
|
||||||
|
con::error("Failed to open file for zone definition file of zone \"{}\".", zone.m_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAssetIncludesAndExcludes(const AssetDumpingContext& context) const
|
||||||
|
{
|
||||||
|
const auto assetTypeCount = context.m_zone.m_pools->GetAssetTypeCount();
|
||||||
|
|
||||||
|
ObjWriting::Configuration.AssetTypesToHandleBitfield = std::vector<bool>(assetTypeCount);
|
||||||
|
|
||||||
|
std::vector<bool> handledSpecifiedAssets(m_args.m_specified_asset_types.size());
|
||||||
|
for (auto i = 0u; i < assetTypeCount; i++)
|
||||||
|
{
|
||||||
|
const auto assetTypeName = std::string(*context.m_zone.m_pools->GetAssetTypeName(i));
|
||||||
|
|
||||||
|
const auto foundSpecifiedEntry = m_args.m_specified_asset_type_map.find(assetTypeName);
|
||||||
|
if (foundSpecifiedEntry != m_args.m_specified_asset_type_map.end())
|
||||||
|
{
|
||||||
|
ObjWriting::Configuration.AssetTypesToHandleBitfield[i] = m_args.m_asset_type_handling == UnlinkerArgs::AssetTypeHandling::INCLUDE;
|
||||||
|
assert(foundSpecifiedEntry->second < handledSpecifiedAssets.size());
|
||||||
|
handledSpecifiedAssets[foundSpecifiedEntry->second] = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ObjWriting::Configuration.AssetTypesToHandleBitfield[i] = m_args.m_asset_type_handling == UnlinkerArgs::AssetTypeHandling::EXCLUDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto anySpecifiedValueInvalid = false;
|
||||||
|
for (auto i = 0u; i < handledSpecifiedAssets.size(); i++)
|
||||||
|
{
|
||||||
|
if (!handledSpecifiedAssets[i])
|
||||||
|
{
|
||||||
|
con::error("Unknown asset type \"{}\"", m_args.m_specified_asset_types[i]);
|
||||||
|
anySpecifiedValueInvalid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anySpecifiedValueInvalid)
|
||||||
|
{
|
||||||
|
con::error("Valid asset types are:");
|
||||||
|
|
||||||
|
auto first = true;
|
||||||
|
std::ostringstream ss;
|
||||||
|
for (auto i = 0u; i < assetTypeCount; i++)
|
||||||
|
{
|
||||||
|
const auto assetTypeName = std::string(*context.m_zone.m_pools->GetAssetTypeName(i));
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
ss << ", ";
|
||||||
|
ss << assetTypeName;
|
||||||
|
}
|
||||||
|
con::error(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Performs the tasks specified by the command line arguments on the specified zone.
|
||||||
|
* \param searchPath The search path for obj data.
|
||||||
|
* \param zone The zone to handle.
|
||||||
|
* \return \c true if handling the zone was successful, otherwise \c false
|
||||||
|
*/
|
||||||
|
bool HandleZone(ISearchPath& searchPath, Zone& zone) const
|
||||||
|
{
|
||||||
|
if (m_args.m_task == UnlinkerArgs::ProcessingTask::LIST)
|
||||||
|
{
|
||||||
|
const ContentPrinter printer(zone);
|
||||||
|
printer.PrintContent();
|
||||||
|
}
|
||||||
|
else if (m_args.m_task == UnlinkerArgs::ProcessingTask::DUMP)
|
||||||
|
{
|
||||||
|
const auto outputFolderPathStr = m_args.GetOutputFolderPathForZone(zone);
|
||||||
|
const fs::path outputFolderPath(outputFolderPathStr);
|
||||||
|
fs::create_directories(outputFolderPath);
|
||||||
|
|
||||||
|
fs::path zoneDefinitionFileFolder(outputFolderPath);
|
||||||
|
zoneDefinitionFileFolder.append("zone_source");
|
||||||
|
fs::create_directories(zoneDefinitionFileFolder);
|
||||||
|
|
||||||
|
if (!WriteZoneDefinitionFile(zone, zoneDefinitionFileFolder))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
OutputPathFilesystem outputFolderOutputPath(outputFolderPath);
|
||||||
|
AssetDumpingContext context(zone, outputFolderPathStr, outputFolderOutputPath, searchPath, std::nullopt);
|
||||||
|
|
||||||
|
std::ofstream gdtStream;
|
||||||
|
if (m_args.m_use_gdt)
|
||||||
|
{
|
||||||
|
if (!OpenGdtFile(zone, outputFolderPath, gdtStream))
|
||||||
|
return false;
|
||||||
|
auto gdt = std::make_unique<GdtOutputStream>(gdtStream);
|
||||||
|
gdt->BeginStream();
|
||||||
|
|
||||||
|
const auto* game = IGame::GetGameById(zone.m_game_id);
|
||||||
|
gdt->WriteVersion(GdtVersion(game->GetShortName(), 1));
|
||||||
|
|
||||||
|
context.m_gdt = std::move(gdt);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAssetIncludesAndExcludes(context);
|
||||||
|
|
||||||
|
const auto* objWriter = IObjWriter::GetObjWriterForGame(zone.m_game_id);
|
||||||
|
|
||||||
|
auto result = objWriter->DumpZone(context);
|
||||||
|
|
||||||
|
if (m_args.m_use_gdt)
|
||||||
|
{
|
||||||
|
context.m_gdt->EndStream();
|
||||||
|
gdtStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
con::error("Dumping zone failed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadZones(UnlinkerPaths& paths)
|
||||||
|
{
|
||||||
|
for (const auto& zonePath : m_args.m_zones_to_load)
|
||||||
|
{
|
||||||
|
if (!fs::is_regular_file(zonePath))
|
||||||
|
{
|
||||||
|
con::error("Could not find file \"{}\".", zonePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
|
||||||
|
|
||||||
|
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
|
if (!maybeZone)
|
||||||
|
{
|
||||||
|
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
|
||||||
|
con::debug("Loaded zone \"{}\"", zone->m_name);
|
||||||
|
|
||||||
|
if (ShouldLoadObj())
|
||||||
|
{
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
||||||
|
objLoader->LoadReferencedContainersForZone(*searchPathsForZone, *zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_loaded_zones.emplace_back(std::move(zone));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnloadZones()
|
||||||
|
{
|
||||||
|
for (auto i = m_loaded_zones.rbegin(); i != m_loaded_zones.rend(); ++i)
|
||||||
|
{
|
||||||
|
auto& loadedZone = *i;
|
||||||
|
|
||||||
|
// Copy zone name since we deallocate before logging
|
||||||
|
const auto zoneName = loadedZone->m_name;
|
||||||
|
|
||||||
|
if (ShouldLoadObj())
|
||||||
|
{
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(loadedZone->m_game_id);
|
||||||
|
objLoader->UnloadContainersOfZone(*loadedZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedZone.reset();
|
||||||
|
|
||||||
|
con::debug("Unloaded zone \"{}\"", zoneName);
|
||||||
|
}
|
||||||
|
m_loaded_zones.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnlinkZones(UnlinkerPaths& paths) const
|
||||||
|
{
|
||||||
|
for (const auto& zonePath : m_args.m_zones_to_unlink)
|
||||||
|
{
|
||||||
|
if (!fs::is_regular_file(zonePath))
|
||||||
|
{
|
||||||
|
con::error("Could not find file \"{}\".", zonePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto zoneDirectory = fs::path(zonePath).remove_filename();
|
||||||
|
if (zoneDirectory.empty())
|
||||||
|
zoneDirectory = fs::current_path();
|
||||||
|
auto absoluteZoneDirectory = absolute(zoneDirectory).string();
|
||||||
|
|
||||||
|
auto searchPathsForZone = paths.GetSearchPathsForZone(absoluteZoneDirectory);
|
||||||
|
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(zonePath, std::nullopt);
|
||||||
|
if (!maybeZone)
|
||||||
|
{
|
||||||
|
con::error("Failed to load zone \"{}\": {}", zonePath, maybeZone.error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
|
||||||
|
con::debug("Loaded zone \"{}\"", zone->m_name);
|
||||||
|
|
||||||
|
const auto* objLoader = IObjLoader::GetObjLoaderForGame(zone->m_game_id);
|
||||||
|
if (ShouldLoadObj())
|
||||||
|
objLoader->LoadReferencedContainersForZone(*searchPathsForZone, *zone);
|
||||||
|
|
||||||
|
if (!HandleZone(*searchPathsForZone, *zone))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ShouldLoadObj())
|
||||||
|
objLoader->UnloadContainersOfZone(*zone);
|
||||||
|
|
||||||
|
// Copy zone name for using it after freeing the zone
|
||||||
|
std::string zoneName = zone->m_name;
|
||||||
|
zone.reset();
|
||||||
|
con::debug("Unloaded zone \"{}\"", zoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlinkerArgs m_args;
|
||||||
|
std::vector<std::unique_ptr<Zone>> m_loaded_zones;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<Unlinker> Unlinker::Create(UnlinkerArgs args)
|
||||||
|
{
|
||||||
|
return std::make_unique<UnlinkerImpl>(std::move(args));
|
||||||
|
}
|
||||||
19
src/Unlinking/Unlinker.h
Normal file
19
src/Unlinking/Unlinker.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "UnlinkerArgs.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Unlinker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Unlinker() = default;
|
||||||
|
|
||||||
|
static std::unique_ptr<Unlinker> Create(UnlinkerArgs args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Starts the Unlinker application logic.
|
||||||
|
* \return \c true if the application was successful or \c false if an error occurred.
|
||||||
|
*/
|
||||||
|
virtual bool Start() = 0;
|
||||||
|
};
|
||||||
@@ -225,6 +225,20 @@ function ZoneCode:allTestFiles()
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ZoneCode:allMarkFiles()
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
for game, assets in pairs(self.Assets) do
|
||||||
|
for i, assetName in ipairs(assets) do
|
||||||
|
local assetNameLower = string.lower(assetName)
|
||||||
|
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.cpp")
|
||||||
|
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.h")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
function ZoneCode:allLoadFiles()
|
function ZoneCode:allLoadFiles()
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
@@ -233,8 +247,6 @@ function ZoneCode:allLoadFiles()
|
|||||||
local assetNameLower = string.lower(assetName)
|
local assetNameLower = string.lower(assetName)
|
||||||
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.cpp")
|
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.cpp")
|
||||||
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.h")
|
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.h")
|
||||||
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.cpp")
|
|
||||||
table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.h")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,9 @@ namespace
|
|||||||
LINE("")
|
LINE("")
|
||||||
LINEF("#include \"{0}_load_db.h\"", Lower(m_env.m_asset->m_definition->m_name))
|
LINEF("#include \"{0}_load_db.h\"", Lower(m_env.m_asset->m_definition->m_name))
|
||||||
LINE("")
|
LINE("")
|
||||||
LINEF("#include \"{0}_mark_db.h\"", Lower(m_env.m_asset->m_definition->m_name))
|
LINEF("#include \"Game/{0}/AssetMarker{0}.h\"", m_env.m_game)
|
||||||
|
LINE("")
|
||||||
|
LINE("#include \"Loading/AssetInfoCollector.h\"")
|
||||||
|
|
||||||
if (!m_env.m_referenced_assets.empty())
|
if (!m_env.m_referenced_assets.empty())
|
||||||
{
|
{
|
||||||
@@ -236,11 +238,6 @@ namespace
|
|||||||
return std::format("Loader_{0}", asset->m_definition->m_name);
|
return std::format("Loader_{0}", asset->m_definition->m_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string MarkerClassName(const StructureInformation* asset)
|
|
||||||
{
|
|
||||||
return std::format("Marker_{0}", asset->m_definition->m_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string VariableDecl(const DataDefinition* def)
|
static std::string VariableDecl(const DataDefinition* def)
|
||||||
{
|
{
|
||||||
return std::format("{0}* var{1};", def->GetFullName(), MakeSafeTypeName(def));
|
return std::format("{0}* var{1};", def->GetFullName(), MakeSafeTypeName(def));
|
||||||
@@ -2155,14 +2152,16 @@ namespace
|
|||||||
|
|
||||||
LINE("assert(pAsset != nullptr);")
|
LINE("assert(pAsset != nullptr);")
|
||||||
LINE("")
|
LINE("")
|
||||||
LINEF("{0} marker(m_zone);", MarkerClassName(m_env.m_asset))
|
LINE("AssetInfoCollector assetInfo(m_zone);")
|
||||||
|
LINEF("AssetMarker<{0}> marker(assetInfo);", m_env.m_asset->m_asset_name)
|
||||||
LINE("marker.Mark(*pAsset);")
|
LINE("marker.Mark(*pAsset);")
|
||||||
LINE("")
|
LINE("")
|
||||||
LINEF("auto* reallocatedAsset = m_zone.Memory().Alloc<{0}>();", info->m_definition->GetFullName())
|
LINEF("auto* reallocatedAsset = m_zone.Memory().Alloc<{0}>();", info->m_definition->GetFullName())
|
||||||
LINEF("std::memcpy(reallocatedAsset, *pAsset, sizeof({0}));", info->m_definition->GetFullName())
|
LINEF("std::memcpy(reallocatedAsset, *pAsset, sizeof({0}));", info->m_definition->GetFullName())
|
||||||
LINE("")
|
LINE("")
|
||||||
LINEF("m_asset_info = reinterpret_cast<XAssetInfo<{0}>*>(LinkAsset(AssetNameAccessor<{1}>()(**pAsset), reallocatedAsset, marker.GetDependencies(), "
|
LINEF("m_asset_info = reinterpret_cast<XAssetInfo<{0}>*>(LinkAsset(AssetName<{1}>(**pAsset), reallocatedAsset, "
|
||||||
"marker.GetUsedScriptStrings(), marker.GetIndirectAssetReferences()));",
|
"assetInfo.GetDependencies(), "
|
||||||
|
"assetInfo.GetUsedScriptStrings(), assetInfo.GetIndirectAssetReferences()));",
|
||||||
info->m_definition->GetFullName(),
|
info->m_definition->GetFullName(),
|
||||||
info->m_asset_name)
|
info->m_asset_name)
|
||||||
LINE("*pAsset = m_asset_info->Asset();")
|
LINE("*pAsset = m_asset_info->Asset();")
|
||||||
@@ -2186,7 +2185,7 @@ namespace
|
|||||||
LINE("")
|
LINE("")
|
||||||
LINE("if (m_asset_info == nullptr && *pAsset != nullptr)")
|
LINE("if (m_asset_info == nullptr && *pAsset != nullptr)")
|
||||||
m_intendation++;
|
m_intendation++;
|
||||||
LINEF("m_asset_info = reinterpret_cast<XAssetInfo<{0}>*>(GetAssetInfo(AssetNameAccessor<{1}>()(**pAsset)));",
|
LINEF("m_asset_info = reinterpret_cast<XAssetInfo<{0}>*>(GetAssetInfo(AssetName<{1}>(**pAsset)));",
|
||||||
m_env.m_asset->m_definition->GetFullName(),
|
m_env.m_asset->m_definition->GetFullName(),
|
||||||
m_env.m_asset->m_asset_name)
|
m_env.m_asset->m_asset_name)
|
||||||
m_intendation--;
|
m_intendation--;
|
||||||
|
|||||||
@@ -32,14 +32,15 @@ namespace
|
|||||||
LINE("#pragma once")
|
LINE("#pragma once")
|
||||||
LINE("")
|
LINE("")
|
||||||
LINEF("#include \"Game/{0}/{0}.h\"", m_env.m_game)
|
LINEF("#include \"Game/{0}/{0}.h\"", m_env.m_game)
|
||||||
LINE("#include \"Loading/AssetMarker.h\"")
|
LINE("#include \"Marking/BaseAssetMarker.h\"")
|
||||||
|
LINE("#include \"Marking/AssetVisitor.h\"")
|
||||||
LINE("")
|
LINE("")
|
||||||
LINE("#include <string>")
|
LINE("#include <string>")
|
||||||
LINE("")
|
LINE("")
|
||||||
LINEF("namespace {0}", m_env.m_game)
|
LINEF("namespace {0}", m_env.m_game)
|
||||||
LINE("{")
|
LINE("{")
|
||||||
m_intendation++;
|
m_intendation++;
|
||||||
LINEF("class {0} final : public AssetMarker", MarkerClassName(m_env.m_asset))
|
LINEF("class {0} final : public BaseAssetMarker", MarkerClassName(m_env.m_asset))
|
||||||
LINE("{")
|
LINE("{")
|
||||||
m_intendation++;
|
m_intendation++;
|
||||||
|
|
||||||
@@ -48,7 +49,6 @@ namespace
|
|||||||
m_intendation++;
|
m_intendation++;
|
||||||
PrintHeaderConstructor();
|
PrintHeaderConstructor();
|
||||||
PrintHeaderMainMarkMethodDeclaration(m_env.m_asset);
|
PrintHeaderMainMarkMethodDeclaration(m_env.m_asset);
|
||||||
PrintHeaderGetAssetInfoMethodDeclaration(m_env.m_asset);
|
|
||||||
LINE("")
|
LINE("")
|
||||||
|
|
||||||
m_intendation--;
|
m_intendation--;
|
||||||
@@ -107,6 +107,8 @@ namespace
|
|||||||
LINE("};")
|
LINE("};")
|
||||||
m_intendation--;
|
m_intendation--;
|
||||||
LINE("}")
|
LINE("}")
|
||||||
|
LINE("")
|
||||||
|
LINEF("DEFINE_MARKER_CLASS_FOR_ASSET({0}::{1}, {0}::{2})", m_env.m_game, m_env.m_asset->m_asset_name, MarkerClassName(m_env.m_asset))
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source()
|
void Source()
|
||||||
@@ -136,8 +138,6 @@ namespace
|
|||||||
PrintConstructorMethod();
|
PrintConstructorMethod();
|
||||||
LINE("")
|
LINE("")
|
||||||
PrintMainMarkMethod();
|
PrintMainMarkMethod();
|
||||||
LINE("")
|
|
||||||
PrintGetAssetInfoMethod();
|
|
||||||
|
|
||||||
for (const auto* type : m_env.m_used_types)
|
for (const auto* type : m_env.m_used_types)
|
||||||
{
|
{
|
||||||
@@ -210,14 +210,9 @@ namespace
|
|||||||
LINEF("void Mark_{0}();", MakeSafeTypeName(info->m_definition))
|
LINEF("void Mark_{0}();", MakeSafeTypeName(info->m_definition))
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintHeaderGetAssetInfoMethodDeclaration(const StructureInformation* info) const
|
|
||||||
{
|
|
||||||
LINEF("XAssetInfo<{0}>* GetAssetInfo({0}* pAsset) const;", info->m_definition->GetFullName())
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintHeaderConstructor() const
|
void PrintHeaderConstructor() const
|
||||||
{
|
{
|
||||||
LINEF("{0}(Zone& zone);", MarkerClassName(m_env.m_asset))
|
LINEF("explicit {0}(AssetVisitor& visitor);", MarkerClassName(m_env.m_asset))
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintHeaderMainMarkMethodDeclaration(const StructureInformation* info) const
|
void PrintHeaderMainMarkMethodDeclaration(const StructureInformation* info) const
|
||||||
@@ -237,10 +232,10 @@ namespace
|
|||||||
|
|
||||||
void PrintConstructorMethod()
|
void PrintConstructorMethod()
|
||||||
{
|
{
|
||||||
LINEF("{0}::{0}(Zone& zone)", MarkerClassName(m_env.m_asset))
|
LINEF("{0}::{0}(AssetVisitor& visitor)", MarkerClassName(m_env.m_asset))
|
||||||
|
|
||||||
m_intendation++;
|
m_intendation++;
|
||||||
LINEF(": AssetMarker({0}::EnumEntry, zone)", m_env.m_asset->m_asset_name)
|
LINE(": BaseAssetMarker(visitor)")
|
||||||
m_intendation--;
|
m_intendation--;
|
||||||
|
|
||||||
LINE("{")
|
LINE("{")
|
||||||
@@ -286,7 +281,7 @@ namespace
|
|||||||
|
|
||||||
if (info && StructureComputations(info).IsAsset())
|
if (info && StructureComputations(info).IsAsset())
|
||||||
{
|
{
|
||||||
LINEF("AddDependency({0}(m_zone).GetAssetInfo(*{1}));", MarkerClassName(info), MakeTypePtrVarName(def))
|
LINEF("Mark_Dependency<{0}>(*{1});", info->m_asset_name, MakeTypePtrVarName(def))
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -413,7 +408,7 @@ namespace
|
|||||||
{
|
{
|
||||||
if (loadType == MemberLoadType::SINGLE_POINTER)
|
if (loadType == MemberLoadType::SINGLE_POINTER)
|
||||||
{
|
{
|
||||||
LINEF("AddDependency({0}(m_zone).GetAssetInfo({1}));", MarkerClassName(member->m_type), MakeMemberAccess(info, member, modifier))
|
LINEF("Mark_Dependency<{0}>({1});", member->m_type->m_asset_name, MakeMemberAccess(info, member, modifier))
|
||||||
}
|
}
|
||||||
else if (loadType == MemberLoadType::POINTER_ARRAY)
|
else if (loadType == MemberLoadType::POINTER_ARRAY)
|
||||||
{
|
{
|
||||||
@@ -752,20 +747,6 @@ namespace
|
|||||||
LINE("}")
|
LINE("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintGetAssetInfoMethod()
|
|
||||||
{
|
|
||||||
LINEF("XAssetInfo<{0}>* {1}::GetAssetInfo({0}* pAsset) const", m_env.m_asset->m_definition->GetFullName(), MarkerClassName(m_env.m_asset))
|
|
||||||
LINE("{")
|
|
||||||
m_intendation++;
|
|
||||||
|
|
||||||
LINEF("return reinterpret_cast<XAssetInfo<{0}>*>(GetAssetInfoByName(AssetNameAccessor<{1}>()(*pAsset)));",
|
|
||||||
m_env.m_asset->m_definition->GetFullName(),
|
|
||||||
m_env.m_asset->m_asset_name)
|
|
||||||
|
|
||||||
m_intendation--;
|
|
||||||
LINE("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintMainMarkMethod()
|
void PrintMainMarkMethod()
|
||||||
{
|
{
|
||||||
LINEF("void {0}::Mark({1}* pAsset)", MarkerClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName())
|
LINEF("void {0}::Mark({1}* pAsset)", MarkerClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName())
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ namespace
|
|||||||
"{0}::{0}({1}* asset, const Zone& zone, IZoneOutputStream& stream)", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName())
|
"{0}::{0}({1}* asset, const Zone& zone, IZoneOutputStream& stream)", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName())
|
||||||
|
|
||||||
m_intendation++;
|
m_intendation++;
|
||||||
LINEF(": AssetWriter(zone.m_pools->GetAssetOrAssetReference({0}::EnumEntry, AssetNameAccessor<{0}>()(*asset)), zone, stream)",
|
LINEF(": AssetWriter(zone.m_pools->GetAssetOrAssetReference({0}::EnumEntry, NonReferenceAssetName(AssetName<{0}>(*asset))), zone, stream)",
|
||||||
m_env.m_asset->m_asset_name)
|
m_env.m_asset->m_asset_name)
|
||||||
m_intendation--;
|
m_intendation--;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ function ZoneCommon:include(includes)
|
|||||||
ObjCommon:include(includes)
|
ObjCommon:include(includes)
|
||||||
Parser:include(includes)
|
Parser:include(includes)
|
||||||
Cryptography:include(includes)
|
Cryptography:include(includes)
|
||||||
|
ZoneCode:include(includes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ function ZoneCommon:link(links)
|
|||||||
links:linkto(Parser)
|
links:linkto(Parser)
|
||||||
links:linkto(Utils)
|
links:linkto(Utils)
|
||||||
links:linkto(lzx)
|
links:linkto(lzx)
|
||||||
|
ZoneCode:use()
|
||||||
end
|
end
|
||||||
|
|
||||||
function ZoneCommon:use()
|
function ZoneCommon:use()
|
||||||
@@ -43,9 +45,20 @@ function ZoneCommon:project()
|
|||||||
|
|
||||||
files {
|
files {
|
||||||
path.join(folder, "ZoneCommon/**.h"),
|
path.join(folder, "ZoneCommon/**.h"),
|
||||||
path.join(folder, "ZoneCommon/**.cpp")
|
path.join(folder, "ZoneCommon/**.cpp"),
|
||||||
|
ZoneCode:allMarkFiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
vpaths {
|
||||||
|
["*"] = {
|
||||||
|
path.join(folder, "ZoneCommon"),
|
||||||
|
path.join(BuildFolder(), "src/ZoneCode")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lzx:include(includes)
|
|
||||||
self:include(includes)
|
self:include(includes)
|
||||||
|
lzx:include(includes)
|
||||||
|
ZoneCode:include(includes)
|
||||||
|
|
||||||
|
ZoneCode:use()
|
||||||
end
|
end
|
||||||
|
|||||||
27
src/ZoneCommon/Game/IW3/AssetMarkerIW3.h
Normal file
27
src/ZoneCommon/Game/IW3/AssetMarkerIW3.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IW3/XAssets/clipmap_t/clipmap_t_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/comworld/comworld_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/font_s/font_s_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/fxeffectdef/fxeffectdef_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/fximpacttable/fximpacttable_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/gameworldmp/gameworldmp_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/gameworldsp/gameworldsp_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/gfximage/gfximage_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/gfxlightdef/gfxlightdef_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/gfxworld/gfxworld_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/loadedsound/loadedsound_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/localizeentry/localizeentry_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/mapents/mapents_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/material/material_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/materialtechniqueset/materialtechniqueset_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/menudef_t/menudef_t_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/menulist/menulist_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/physpreset/physpreset_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/rawfile/rawfile_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/snd_alias_list_t/snd_alias_list_t_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/sndcurve/sndcurve_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/stringtable/stringtable_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/weapondef/weapondef_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/xanimparts/xanimparts_mark_db.h"
|
||||||
|
#include "Game/IW3/XAssets/xmodel/xmodel_mark_db.h"
|
||||||
37
src/ZoneCommon/Game/IW4/AssetMarkerIW4.h
Normal file
37
src/ZoneCommon/Game/IW4/AssetMarkerIW4.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IW4/XAssets/addonmapents/addonmapents_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/clipmap_t/clipmap_t_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/comworld/comworld_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/font_s/font_s_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/fxeffectdef/fxeffectdef_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/fximpacttable/fximpacttable_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/fxworld/fxworld_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/gameworldmp/gameworldmp_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/gameworldsp/gameworldsp_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/gfximage/gfximage_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/gfxlightdef/gfxlightdef_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/gfxworld/gfxworld_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/leaderboarddef/leaderboarddef_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/loadedsound/loadedsound_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/localizeentry/localizeentry_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/mapents/mapents_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/material/material_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/materialpixelshader/materialpixelshader_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/materialtechniqueset/materialtechniqueset_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/materialvertexdeclaration/materialvertexdeclaration_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/materialvertexshader/materialvertexshader_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/menudef_t/menudef_t_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/menulist/menulist_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/physcollmap/physcollmap_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/physpreset/physpreset_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/rawfile/rawfile_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/snd_alias_list_t/snd_alias_list_t_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/sndcurve/sndcurve_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/stringtable/stringtable_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/structureddatadefset/structureddatadefset_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/tracerdef/tracerdef_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/vehicledef/vehicledef_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/weaponcompletedef/weaponcompletedef_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/xanimparts/xanimparts_mark_db.h"
|
||||||
|
#include "Game/IW4/XAssets/xmodel/xmodel_mark_db.h"
|
||||||
42
src/ZoneCommon/Game/IW5/AssetMarkerIW5.h
Normal file
42
src/ZoneCommon/Game/IW5/AssetMarkerIW5.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IW5/XAssets/addonmapents/addonmapents_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/clipmap_t/clipmap_t_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/comworld/comworld_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/font_s/font_s_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/fxeffectdef/fxeffectdef_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/fximpacttable/fximpacttable_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/fxworld/fxworld_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/gfximage/gfximage_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/gfxlightdef/gfxlightdef_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/gfxworld/gfxworld_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/glassworld/glassworld_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/leaderboarddef/leaderboarddef_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/loadedsound/loadedsound_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/localizeentry/localizeentry_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/mapents/mapents_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/material/material_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/materialpixelshader/materialpixelshader_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/materialtechniqueset/materialtechniqueset_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/materialvertexdeclaration/materialvertexdeclaration_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/materialvertexshader/materialvertexshader_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/menudef_t/menudef_t_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/menulist/menulist_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/pathdata/pathdata_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/physcollmap/physcollmap_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/physpreset/physpreset_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/rawfile/rawfile_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/scriptfile/scriptfile_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/snd_alias_list_t/snd_alias_list_t_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/sndcurve/sndcurve_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/stringtable/stringtable_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/structureddatadefset/structureddatadefset_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/surfacefxtable/surfacefxtable_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/tracerdef/tracerdef_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/vehicledef/vehicledef_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/vehicletrack/vehicletrack_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/weaponattachment/weaponattachment_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/weaponcompletedef/weaponcompletedef_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/xanimparts/xanimparts_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/xmodel/xmodel_mark_db.h"
|
||||||
|
#include "Game/IW5/XAssets/xmodelsurfs/xmodelsurfs_mark_db.h"
|
||||||
34
src/ZoneCommon/Game/T5/AssetMarkerT5.h
Normal file
34
src/ZoneCommon/Game/T5/AssetMarkerT5.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/T5/XAssets/clipmap_t/clipmap_t_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/comworld/comworld_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/ddlroot_t/ddlroot_t_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/destructibledef/destructibledef_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/emblemset/emblemset_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/font_s/font_s_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/fxeffectdef/fxeffectdef_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/fximpacttable/fximpacttable_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/gameworldmp/gameworldmp_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/gameworldsp/gameworldsp_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/gfximage/gfximage_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/gfxlightdef/gfxlightdef_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/gfxworld/gfxworld_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/glasses/glasses_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/localizeentry/localizeentry_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/mapents/mapents_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/material/material_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/materialtechniqueset/materialtechniqueset_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/menudef_t/menudef_t_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/menulist/menulist_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/packindex/packindex_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/physconstraints/physconstraints_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/physpreset/physpreset_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/rawfile/rawfile_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/sndbank/sndbank_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/snddriverglobals/snddriverglobals_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/sndpatch/sndpatch_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/stringtable/stringtable_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/weaponvariantdef/weaponvariantdef_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/xanimparts/xanimparts_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/xglobals/xglobals_mark_db.h"
|
||||||
|
#include "Game/T5/XAssets/xmodel/xmodel_mark_db.h"
|
||||||
50
src/ZoneCommon/Game/T6/AssetMarkerT6.h
Normal file
50
src/ZoneCommon/Game/T6/AssetMarkerT6.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/T6/XAssets/addonmapents/addonmapents_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/clipmap_t/clipmap_t_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/comworld/comworld_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/ddlroot_t/ddlroot_t_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/destructibledef/destructibledef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/emblemset/emblemset_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/font_s/font_s_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/fonticon/fonticon_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/footstepfxtabledef/footstepfxtabledef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/footsteptabledef/footsteptabledef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/fxeffectdef/fxeffectdef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/fximpacttable/fximpacttable_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/gameworldmp/gameworldmp_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/gameworldsp/gameworldsp_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/gfximage/gfximage_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/gfxlightdef/gfxlightdef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/gfxworld/gfxworld_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/glasses/glasses_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/keyvaluepairs/keyvaluepairs_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/leaderboarddef/leaderboarddef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/localizeentry/localizeentry_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/mapents/mapents_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/material/material_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/materialtechniqueset/materialtechniqueset_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/memoryblock/memoryblock_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/menudef_t/menudef_t_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/menulist/menulist_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/physconstraints/physconstraints_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/physpreset/physpreset_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/qdb/qdb_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/rawfile/rawfile_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/scriptparsetree/scriptparsetree_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/skinnedvertsdef/skinnedvertsdef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/slug/slug_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/sndbank/sndbank_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/snddriverglobals/snddriverglobals_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/sndpatch/sndpatch_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/stringtable/stringtable_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/tracerdef/tracerdef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/vehicledef/vehicledef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/weaponattachment/weaponattachment_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/weaponattachmentunique/weaponattachmentunique_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/weaponcamo/weaponcamo_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/weaponvariantdef/weaponvariantdef_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/xanimparts/xanimparts_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/xglobals/xglobals_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/xmodel/xmodel_mark_db.h"
|
||||||
|
#include "Game/T6/XAssets/zbarrierdef/zbarrierdef_mark_db.h"
|
||||||
29
src/ZoneCommon/Marking/AssetVisitor.h
Normal file
29
src/ZoneCommon/Marking/AssetVisitor.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Pool/XAssetInfo.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
class AssetVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~AssetVisitor() = default;
|
||||||
|
|
||||||
|
virtual std::optional<XAssetInfoGeneric*> Visit_Dependency(asset_type_t assetType, const char* assetName)
|
||||||
|
{
|
||||||
|
// Do nothing by default
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::optional<scr_string_t> Visit_ScriptString(scr_string_t scriptString)
|
||||||
|
{
|
||||||
|
// Do nothing by default
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Visit_IndirectAssetRef(asset_type_t assetType, const char* assetName)
|
||||||
|
{
|
||||||
|
// Do nothing by default
|
||||||
|
}
|
||||||
|
};
|
||||||
40
src/ZoneCommon/Marking/BaseAssetMarker.cpp
Normal file
40
src/ZoneCommon/Marking/BaseAssetMarker.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include "BaseAssetMarker.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
BaseAssetMarker::BaseAssetMarker(AssetVisitor& visitor)
|
||||||
|
: m_visitor(visitor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseAssetMarker::Mark_ScriptString(scr_string_t& scriptString) const
|
||||||
|
{
|
||||||
|
const auto result = m_visitor.Visit_ScriptString(scriptString);
|
||||||
|
if (result.has_value())
|
||||||
|
scriptString = *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseAssetMarker::MarkArray_ScriptString(scr_string_t* scriptStringArray, const size_t count) const
|
||||||
|
{
|
||||||
|
assert(scriptStringArray != nullptr);
|
||||||
|
|
||||||
|
for (size_t index = 0; index < count; index++)
|
||||||
|
Mark_ScriptString(scriptStringArray[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseAssetMarker::Mark_IndirectAssetRef(const asset_type_t assetType, const char* assetName) const
|
||||||
|
{
|
||||||
|
if (!assetName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_visitor.Visit_IndirectAssetRef(assetType, assetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseAssetMarker::MarkArray_IndirectAssetRef(const asset_type_t assetType, const char** assetNames, const size_t count) const
|
||||||
|
{
|
||||||
|
assert(assetNames != nullptr);
|
||||||
|
|
||||||
|
for (size_t index = 0; index < count; index++)
|
||||||
|
Mark_IndirectAssetRef(assetType, assetNames[index]);
|
||||||
|
}
|
||||||
45
src/ZoneCommon/Marking/BaseAssetMarker.h
Normal file
45
src/ZoneCommon/Marking/BaseAssetMarker.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IAsset.h"
|
||||||
|
#include "Marking/AssetVisitor.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
class BaseAssetMarker
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
explicit BaseAssetMarker(AssetVisitor& visitor);
|
||||||
|
|
||||||
|
template<typename AssetType> void Mark_Dependency(std::add_lvalue_reference_t<std::add_pointer_t<typename AssetType::Type>> asset)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
|
|
||||||
|
const auto result = m_visitor.Visit_Dependency(AssetType::EnumEntry, AssetName<AssetType>(*asset));
|
||||||
|
if (result.has_value())
|
||||||
|
asset = static_cast<std::add_pointer_t<typename AssetType::Type>>((*result)->m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mark_ScriptString(scr_string_t& scriptString) const;
|
||||||
|
void MarkArray_ScriptString(scr_string_t* scriptStringArray, size_t count) const;
|
||||||
|
|
||||||
|
void Mark_IndirectAssetRef(asset_type_t assetType, const char* assetName) const;
|
||||||
|
void MarkArray_IndirectAssetRef(asset_type_t assetType, const char** assetNames, size_t count) const;
|
||||||
|
|
||||||
|
AssetVisitor& m_visitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename AssetType> struct AssetMarkerWrapper
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
|
||||||
|
// using WrapperClass = WrapperClass;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename AssetType> using AssetMarker = AssetMarkerWrapper<AssetType>::WrapperClass;
|
||||||
|
|
||||||
|
#define DEFINE_MARKER_CLASS_FOR_ASSET(asset, markerClass) \
|
||||||
|
template<> struct AssetMarkerWrapper<asset> \
|
||||||
|
{ \
|
||||||
|
static_assert(std::is_base_of_v<IAssetBase, asset>); \
|
||||||
|
using WrapperClass = markerClass; \
|
||||||
|
};
|
||||||
85
src/ZoneLoading/Loading/AssetInfoCollector.cpp
Normal file
85
src/ZoneLoading/Loading/AssetInfoCollector.cpp
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#include "AssetInfoCollector.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
AssetInfoCollector::AssetInfoCollector(Zone& zone)
|
||||||
|
: m_zone(zone)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<XAssetInfoGeneric*> AssetInfoCollector::GetDependencies() const
|
||||||
|
{
|
||||||
|
std::vector<XAssetInfoGeneric*> dependencies;
|
||||||
|
if (!m_dependencies.empty())
|
||||||
|
{
|
||||||
|
dependencies.reserve(m_dependencies.size());
|
||||||
|
for (auto dependency : m_dependencies)
|
||||||
|
dependencies.push_back(dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<scr_string_t> AssetInfoCollector::GetUsedScriptStrings() const
|
||||||
|
{
|
||||||
|
std::vector<scr_string_t> usedScriptStrings;
|
||||||
|
if (!m_used_script_strings.empty())
|
||||||
|
{
|
||||||
|
usedScriptStrings.reserve(m_used_script_strings.size());
|
||||||
|
for (auto scrString : m_used_script_strings)
|
||||||
|
usedScriptStrings.push_back(scrString);
|
||||||
|
|
||||||
|
std::ranges::sort(usedScriptStrings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return usedScriptStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IndirectAssetReference> AssetInfoCollector::GetIndirectAssetReferences() const
|
||||||
|
{
|
||||||
|
std::vector<IndirectAssetReference> assetReferences;
|
||||||
|
if (!m_indirect_asset_references.empty())
|
||||||
|
{
|
||||||
|
assetReferences.reserve(m_indirect_asset_references.size());
|
||||||
|
for (const auto& assetReference : m_indirect_asset_references)
|
||||||
|
assetReferences.emplace_back(assetReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
return assetReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<XAssetInfoGeneric*> AssetInfoCollector::Visit_Dependency(const asset_type_t assetType, const char* assetName)
|
||||||
|
{
|
||||||
|
auto* assetInfo = m_zone.m_pools->GetAsset(assetType, assetName);
|
||||||
|
if (assetInfo == nullptr)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
const auto existingEntry = m_dependencies.find(assetInfo);
|
||||||
|
if (existingEntry != m_dependencies.end())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
m_dependencies.emplace(assetInfo);
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<scr_string_t> AssetInfoCollector::Visit_ScriptString(scr_string_t scriptString)
|
||||||
|
{
|
||||||
|
assert(scriptString < m_zone.m_script_strings.Count());
|
||||||
|
|
||||||
|
if (scriptString >= m_zone.m_script_strings.Count())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
m_used_script_strings.emplace(scriptString);
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetInfoCollector::Visit_IndirectAssetRef(asset_type_t assetType, const char* assetName)
|
||||||
|
{
|
||||||
|
if (!assetName || !assetName[0])
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_indirect_asset_references.emplace(assetType, assetName);
|
||||||
|
}
|
||||||
31
src/ZoneLoading/Loading/AssetInfoCollector.h
Normal file
31
src/ZoneLoading/Loading/AssetInfoCollector.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Marking/AssetVisitor.h"
|
||||||
|
#include "Pool/XAssetInfo.h"
|
||||||
|
#include "Zone/ZoneTypes.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class AssetInfoCollector : public AssetVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AssetInfoCollector(Zone& zone);
|
||||||
|
~AssetInfoCollector() override = default;
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<XAssetInfoGeneric*> GetDependencies() const;
|
||||||
|
[[nodiscard]] std::vector<scr_string_t> GetUsedScriptStrings() const;
|
||||||
|
[[nodiscard]] std::vector<IndirectAssetReference> GetIndirectAssetReferences() const;
|
||||||
|
|
||||||
|
std::optional<XAssetInfoGeneric*> Visit_Dependency(asset_type_t assetType, const char* assetName) override;
|
||||||
|
std::optional<scr_string_t> Visit_ScriptString(scr_string_t scriptString) override;
|
||||||
|
void Visit_IndirectAssetRef(asset_type_t assetType, const char* assetName) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_set<XAssetInfoGeneric*> m_dependencies;
|
||||||
|
std::unordered_set<scr_string_t> m_used_script_strings;
|
||||||
|
std::unordered_set<IndirectAssetReference> m_indirect_asset_references;
|
||||||
|
|
||||||
|
Zone& m_zone;
|
||||||
|
};
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
#include "AssetMarker.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
AssetMarker::AssetMarker(const asset_type_t assetType, Zone& zone)
|
|
||||||
: m_zone(zone),
|
|
||||||
m_asset_type(assetType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetMarker::AddDependency(XAssetInfoGeneric* assetInfo)
|
|
||||||
{
|
|
||||||
if (assetInfo == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto existingEntry = m_dependencies.find(assetInfo);
|
|
||||||
if (existingEntry != m_dependencies.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_dependencies.emplace(assetInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetMarker::Mark_ScriptString(const scr_string_t scrString)
|
|
||||||
{
|
|
||||||
assert(scrString < m_zone.m_script_strings.Count());
|
|
||||||
|
|
||||||
if (scrString >= m_zone.m_script_strings.Count())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_used_script_strings.emplace(scrString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetMarker::MarkArray_ScriptString(const scr_string_t* scrStringArray, const size_t count)
|
|
||||||
{
|
|
||||||
assert(scrStringArray != nullptr);
|
|
||||||
|
|
||||||
for (size_t index = 0; index < count; index++)
|
|
||||||
Mark_ScriptString(scrStringArray[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetMarker::Mark_IndirectAssetRef(asset_type_t type, const char* assetRefName)
|
|
||||||
{
|
|
||||||
if (!assetRefName || !assetRefName[0])
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_indirect_asset_references.emplace(type, assetRefName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetMarker::MarkArray_IndirectAssetRef(const asset_type_t type, const char** assetRefNames, const size_t count)
|
|
||||||
{
|
|
||||||
assert(assetRefNames != nullptr);
|
|
||||||
|
|
||||||
for (size_t index = 0; index < count; index++)
|
|
||||||
Mark_IndirectAssetRef(type, assetRefNames[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
XAssetInfoGeneric* AssetMarker::GetAssetInfoByName(const std::string& name) const
|
|
||||||
{
|
|
||||||
return m_zone.m_pools->GetAsset(m_asset_type, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<XAssetInfoGeneric*> AssetMarker::GetDependencies() const
|
|
||||||
{
|
|
||||||
std::vector<XAssetInfoGeneric*> dependencies;
|
|
||||||
if (!m_dependencies.empty())
|
|
||||||
{
|
|
||||||
dependencies.reserve(m_dependencies.size());
|
|
||||||
for (auto dependency : m_dependencies)
|
|
||||||
dependencies.push_back(dependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<scr_string_t> AssetMarker::GetUsedScriptStrings() const
|
|
||||||
{
|
|
||||||
std::vector<scr_string_t> usedScriptStrings;
|
|
||||||
if (!m_used_script_strings.empty())
|
|
||||||
{
|
|
||||||
usedScriptStrings.reserve(m_used_script_strings.size());
|
|
||||||
for (auto scrString : m_used_script_strings)
|
|
||||||
usedScriptStrings.push_back(scrString);
|
|
||||||
|
|
||||||
std::ranges::sort(usedScriptStrings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return usedScriptStrings;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<IndirectAssetReference> AssetMarker::GetIndirectAssetReferences() const
|
|
||||||
{
|
|
||||||
std::vector<IndirectAssetReference> assetReferences;
|
|
||||||
if (!m_indirect_asset_references.empty())
|
|
||||||
{
|
|
||||||
assetReferences.reserve(m_indirect_asset_references.size());
|
|
||||||
for (const auto& assetReference : m_indirect_asset_references)
|
|
||||||
assetReferences.emplace_back(assetReference);
|
|
||||||
}
|
|
||||||
|
|
||||||
return assetReferences;
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ContentLoaderBase.h"
|
|
||||||
#include "Pool/XAssetInfo.h"
|
|
||||||
#include "Zone/ZoneTypes.h"
|
|
||||||
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
class AssetMarker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
[[nodiscard]] std::vector<XAssetInfoGeneric*> GetDependencies() const;
|
|
||||||
[[nodiscard]] std::vector<scr_string_t> GetUsedScriptStrings() const;
|
|
||||||
[[nodiscard]] std::vector<IndirectAssetReference> GetIndirectAssetReferences() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
AssetMarker(asset_type_t assetType, Zone& zone);
|
|
||||||
|
|
||||||
void AddDependency(XAssetInfoGeneric* assetInfo);
|
|
||||||
|
|
||||||
void Mark_ScriptString(scr_string_t scrString);
|
|
||||||
void MarkArray_ScriptString(const scr_string_t* scrStringArray, size_t count);
|
|
||||||
|
|
||||||
void Mark_IndirectAssetRef(asset_type_t type, const char* assetRefName);
|
|
||||||
void MarkArray_IndirectAssetRef(asset_type_t type, const char** assetRefNames, size_t count);
|
|
||||||
|
|
||||||
[[nodiscard]] XAssetInfoGeneric* GetAssetInfoByName(const std::string& name) const;
|
|
||||||
|
|
||||||
Zone& m_zone;
|
|
||||||
|
|
||||||
private:
|
|
||||||
asset_type_t m_asset_type;
|
|
||||||
|
|
||||||
std::unordered_set<XAssetInfoGeneric*> m_dependencies;
|
|
||||||
std::unordered_set<scr_string_t> m_used_script_strings;
|
|
||||||
std::unordered_set<IndirectAssetReference> m_indirect_asset_references;
|
|
||||||
};
|
|
||||||
@@ -10,6 +10,14 @@ AssetWriter::AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, IZoneOutput
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* AssetWriter::NonReferenceAssetName(const char* assetName)
|
||||||
|
{
|
||||||
|
if (assetName && assetName[0] == ',')
|
||||||
|
return &assetName[1];
|
||||||
|
|
||||||
|
return assetName;
|
||||||
|
}
|
||||||
|
|
||||||
scr_string_t AssetWriter::UseScriptString(const scr_string_t scrString) const
|
scr_string_t AssetWriter::UseScriptString(const scr_string_t scrString) const
|
||||||
{
|
{
|
||||||
assert(scrString < m_asset->m_zone->m_script_strings.Count());
|
assert(scrString < m_asset->m_zone->m_script_strings.Count());
|
||||||
@@ -17,6 +25,7 @@ scr_string_t AssetWriter::UseScriptString(const scr_string_t scrString) const
|
|||||||
if (m_asset->m_zone == &m_zone)
|
if (m_asset->m_zone == &m_zone)
|
||||||
return scrString;
|
return scrString;
|
||||||
|
|
||||||
|
// The asset comes from a different zone, we need to translate it
|
||||||
const auto strValue = m_asset->m_zone->m_script_strings.CValue(scrString);
|
const auto strValue = m_asset->m_zone->m_script_strings.CValue(scrString);
|
||||||
return m_zone.m_script_strings.GetScriptString(strValue);
|
return m_zone.m_script_strings.GetScriptString(strValue);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ class AssetWriter : public ContentWriterBase
|
|||||||
protected:
|
protected:
|
||||||
AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, IZoneOutputStream& stream);
|
AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, IZoneOutputStream& stream);
|
||||||
|
|
||||||
_NODISCARD scr_string_t UseScriptString(scr_string_t scrString) const;
|
[[nodiscard]] static const char* NonReferenceAssetName(const char* assetName);
|
||||||
|
[[nodiscard]] scr_string_t UseScriptString(scr_string_t scrString) const;
|
||||||
void WriteScriptStringArray(bool atStreamStart, size_t count);
|
void WriteScriptStringArray(bool atStreamStart, size_t count);
|
||||||
|
|
||||||
XAssetInfoGeneric* m_asset;
|
XAssetInfoGeneric* m_asset;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ end
|
|||||||
function Catch2Common:link(links)
|
function Catch2Common:link(links)
|
||||||
links:add(self:name())
|
links:add(self:name())
|
||||||
links:linkto(catch2)
|
links:linkto(catch2)
|
||||||
|
links:linkto(Utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Catch2Common:use()
|
function Catch2Common:use()
|
||||||
@@ -45,7 +46,9 @@ function Catch2Common:project()
|
|||||||
|
|
||||||
self:include(includes)
|
self:include(includes)
|
||||||
catch2:include(includes)
|
catch2:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
|
||||||
links:linkto(catch2)
|
links:linkto(catch2)
|
||||||
|
links:linkto(Utils)
|
||||||
links:linkall()
|
links:linkall()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,4 +24,13 @@ namespace oat::paths
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path GetTempDirectory(const std::string& subDir)
|
||||||
|
{
|
||||||
|
auto result = fs::current_path() / "build" / ".tmp" / subDir;
|
||||||
|
if (!fs::is_directory(result))
|
||||||
|
fs::create_directories(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
} // namespace oat::paths
|
} // namespace oat::paths
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace oat::paths
|
namespace oat::paths
|
||||||
{
|
{
|
||||||
std::filesystem::path GetSourceDirectory();
|
std::filesystem::path GetSourceDirectory();
|
||||||
std::filesystem::path GetTestDirectory();
|
std::filesystem::path GetTestDirectory();
|
||||||
std::filesystem::path GetTempDirectory();
|
std::filesystem::path GetTempDirectory();
|
||||||
|
std::filesystem::path GetTempDirectory(const std::string& subDir);
|
||||||
} // namespace oat::paths
|
} // namespace oat::paths
|
||||||
|
|||||||
@@ -1,12 +1,28 @@
|
|||||||
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
#include <catch2/catch_session.hpp>
|
#include <catch2/catch_session.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool ShouldClearTempFolder()
|
||||||
|
{
|
||||||
|
auto* envVar = std::getenv("OAT_KEEP_TMP_DIR");
|
||||||
|
|
||||||
|
return !envVar || !envVar[0] || (envVar[0] == '0' && !envVar[1]);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int main(const int argc, char* argv[])
|
int main(const int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
con::init();
|
||||||
|
con::set_log_level(con::LogLevel::DEBUG);
|
||||||
|
|
||||||
const fs::path absoluteBinDir(fs::canonical(argv[0]).parent_path());
|
const fs::path absoluteBinDir(fs::canonical(argv[0]).parent_path());
|
||||||
|
|
||||||
const auto expectedLibDir = absoluteBinDir.parent_path().parent_path();
|
const auto expectedLibDir = absoluteBinDir.parent_path().parent_path();
|
||||||
@@ -15,24 +31,24 @@ int main(const int argc, char* argv[])
|
|||||||
|
|
||||||
if (absoluteBinDir.filename() != "tests" || expectedLibDir.filename() != "lib" || expectedBuildDir.filename() != "build")
|
if (absoluteBinDir.filename() != "tests" || expectedLibDir.filename() != "lib" || expectedBuildDir.filename() != "build")
|
||||||
{
|
{
|
||||||
std::cerr << std::format("Expected test binary to be in the folder it was compiled into (build/lib/?/tests) but was {}\n", absoluteBinDir.string());
|
con::error("Expected test binary to be in the folder it was compiled into (build/lib/?/tests) but was {}", absoluteBinDir.string());
|
||||||
std::cerr << "Please do not move test executable out of compilation folder\n";
|
con::error("Please do not move test executable out of compilation folder");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto expectedSrcDir = expectedRootDir / "src";
|
const auto expectedSrcDir = expectedRootDir / "src";
|
||||||
if (!fs::is_directory(expectedSrcDir))
|
if (!fs::is_directory(expectedSrcDir))
|
||||||
{
|
{
|
||||||
std::cerr << std::format("Expected source directory to exist in {}, but it did not\n", expectedSrcDir.string());
|
con::error("Expected source directory to exist in {}, but it did not", expectedSrcDir.string());
|
||||||
std::cerr << "Please do not move test executable out of compilation folder\n";
|
con::error("Please do not move test executable out of compilation folder");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto expectedTestDir = expectedRootDir / "test";
|
const auto expectedTestDir = expectedRootDir / "test";
|
||||||
if (!fs::is_directory(expectedTestDir))
|
if (!fs::is_directory(expectedTestDir))
|
||||||
{
|
{
|
||||||
std::cerr << std::format("Expected test directory to exist in {}, but it did not\n", expectedTestDir.string());
|
con::error("Expected test directory to exist in {}, but it did not", expectedTestDir.string());
|
||||||
std::cerr << "Please do not move test executable out of compilation folder\n";
|
con::error("Please do not move test executable out of compilation folder");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +57,16 @@ int main(const int argc, char* argv[])
|
|||||||
const auto result = Catch::Session().run(argc, argv);
|
const auto result = Catch::Session().run(argc, argv);
|
||||||
|
|
||||||
const auto tempDir = expectedBuildDir / ".tmp";
|
const auto tempDir = expectedBuildDir / ".tmp";
|
||||||
if (fs::is_directory(tempDir))
|
if (ShouldClearTempFolder())
|
||||||
fs::remove_all(tempDir);
|
{
|
||||||
|
con::info("Clearing tmp folder. Define env var OAT_KEEP_TMP_DIR=1 to keep it.");
|
||||||
|
if (fs::is_directory(tempDir))
|
||||||
|
fs::remove_all(tempDir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
con::info("Kept tmp dir {} on disk.", tempDir.string());
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
64
test/SystemTests.lua
Normal file
64
test/SystemTests.lua
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
SystemTests = {}
|
||||||
|
|
||||||
|
function SystemTests:include(includes)
|
||||||
|
if includes:handle(self:name()) then
|
||||||
|
includedirs {
|
||||||
|
path.join(TestFolder(), "SystemTests")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SystemTests:link(links)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SystemTests:use()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SystemTests:name()
|
||||||
|
return "SystemTests"
|
||||||
|
end
|
||||||
|
|
||||||
|
function SystemTests:project()
|
||||||
|
local folder = TestFolder()
|
||||||
|
local includes = Includes:create()
|
||||||
|
local links = Links:create()
|
||||||
|
|
||||||
|
project(self:name())
|
||||||
|
targetdir(TargetDirectoryTest)
|
||||||
|
location "%{wks.location}/test/%{prj.name}"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(folder, "SystemTests/**.h"),
|
||||||
|
path.join(folder, "SystemTests/**.cpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
self:include(includes)
|
||||||
|
Catch2Common:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
ZoneLoading:include(includes)
|
||||||
|
ZoneWriting:include(includes)
|
||||||
|
ObjLoading:include(includes)
|
||||||
|
ObjCompiling:include(includes)
|
||||||
|
ObjWriting:include(includes)
|
||||||
|
Linking:include(includes)
|
||||||
|
Unlinking:include(includes)
|
||||||
|
catch2:include(includes)
|
||||||
|
|
||||||
|
Raw:use()
|
||||||
|
|
||||||
|
links:linkto(Utils)
|
||||||
|
links:linkto(ZoneLoading)
|
||||||
|
links:linkto(ZoneWriting)
|
||||||
|
links:linkto(ObjLoading)
|
||||||
|
links:linkto(ObjCompiling)
|
||||||
|
links:linkto(ObjWriting)
|
||||||
|
links:linkto(catch2)
|
||||||
|
links:linkto(Catch2Common)
|
||||||
|
links:linkto(Linking)
|
||||||
|
links:linkto(Unlinking)
|
||||||
|
links:linkall()
|
||||||
|
end
|
||||||
1
test/SystemTests/Game/IW3/Simple/SimpleZone.txt
Normal file
1
test/SystemTests/Game/IW3/Simple/SimpleZone.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is a simple zone.
|
||||||
4
test/SystemTests/Game/IW3/Simple/SimpleZoneIW3.zone
Normal file
4
test/SystemTests/Game/IW3/Simple/SimpleZoneIW3.zone
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
>game,IW3
|
||||||
|
|
||||||
|
rawfile,SimpleZone.txt
|
||||||
|
|
||||||
65
test/SystemTests/Game/IW3/SimpleZoneIW3.cpp
Normal file
65
test/SystemTests/Game/IW3/SimpleZoneIW3.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Game/IW3/GameAssetPoolIW3.h"
|
||||||
|
#include "Linker.h"
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
TEST_CASE("Simple Zone(IW3)", "[iw3][system][simple]")
|
||||||
|
{
|
||||||
|
const auto assetSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW3/Simple").string();
|
||||||
|
const auto sourceSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW3/Simple").string();
|
||||||
|
const auto outputPath = oat::paths::GetTempDirectory("SimpleZoneIW3").string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--asset-search-path",
|
||||||
|
assetSearchPath.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
sourceSearchPath.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPath.c_str(),
|
||||||
|
"SimpleZoneIW3",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
|
||||||
|
// x64 for now produces invalid zones, don't try to load them yet
|
||||||
|
#ifdef ARCH_x86
|
||||||
|
const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneIW3.ff").string();
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt);
|
||||||
|
REQUIRE(maybeZone);
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
auto pools = dynamic_cast<GameAssetPoolIW3*>(zone->m_pools.get());
|
||||||
|
|
||||||
|
REQUIRE(zone->m_game_id == GameId::IW3);
|
||||||
|
REQUIRE(zone->m_platform == GamePlatform::PC);
|
||||||
|
REQUIRE(zone->m_name == "SimpleZoneIW3");
|
||||||
|
REQUIRE(pools->GetTotalAssetCount() == 1);
|
||||||
|
REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
1
test/SystemTests/Game/IW4/Simple/SimpleZone.txt
Normal file
1
test/SystemTests/Game/IW4/Simple/SimpleZone.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is a simple zone.
|
||||||
4
test/SystemTests/Game/IW4/Simple/SimpleZoneIW4.zone
Normal file
4
test/SystemTests/Game/IW4/Simple/SimpleZoneIW4.zone
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
>game,IW4
|
||||||
|
|
||||||
|
rawfile,SimpleZone.txt
|
||||||
|
|
||||||
65
test/SystemTests/Game/IW4/SimpleZoneIW4.cpp
Normal file
65
test/SystemTests/Game/IW4/SimpleZoneIW4.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Game/IW4/GameAssetPoolIW4.h"
|
||||||
|
#include "Linker.h"
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
TEST_CASE("Simple Zone(IW4)", "[iw4][system][simple]")
|
||||||
|
{
|
||||||
|
const auto assetSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW4/Simple").string();
|
||||||
|
const auto sourceSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW4/Simple").string();
|
||||||
|
const auto outputPath = oat::paths::GetTempDirectory("SimpleZoneIW4").string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--asset-search-path",
|
||||||
|
assetSearchPath.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
sourceSearchPath.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPath.c_str(),
|
||||||
|
"SimpleZoneIW4",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
|
||||||
|
// x64 for now produces invalid zones, don't try to load them yet
|
||||||
|
#ifdef ARCH_x86
|
||||||
|
const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneIW4.ff").string();
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt);
|
||||||
|
REQUIRE(maybeZone);
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
auto pools = dynamic_cast<GameAssetPoolIW4*>(zone->m_pools.get());
|
||||||
|
|
||||||
|
REQUIRE(zone->m_game_id == GameId::IW4);
|
||||||
|
REQUIRE(zone->m_platform == GamePlatform::PC);
|
||||||
|
REQUIRE(zone->m_name == "SimpleZoneIW4");
|
||||||
|
REQUIRE(pools->GetTotalAssetCount() == 1);
|
||||||
|
REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
1
test/SystemTests/Game/IW5/Simple/SimpleZone.txt
Normal file
1
test/SystemTests/Game/IW5/Simple/SimpleZone.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is a simple zone.
|
||||||
4
test/SystemTests/Game/IW5/Simple/SimpleZoneIW5.zone
Normal file
4
test/SystemTests/Game/IW5/Simple/SimpleZoneIW5.zone
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
>game,IW5
|
||||||
|
|
||||||
|
rawfile,SimpleZone.txt
|
||||||
|
|
||||||
65
test/SystemTests/Game/IW5/SimpleZoneIW5.cpp
Normal file
65
test/SystemTests/Game/IW5/SimpleZoneIW5.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Game/IW5/GameAssetPoolIW5.h"
|
||||||
|
#include "Linker.h"
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
TEST_CASE("Simple Zone(IW5)", "[iw5][system][simple]")
|
||||||
|
{
|
||||||
|
const auto assetSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW5/Simple").string();
|
||||||
|
const auto sourceSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW5/Simple").string();
|
||||||
|
const auto outputPath = oat::paths::GetTempDirectory("SimpleZoneIW5").string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--asset-search-path",
|
||||||
|
assetSearchPath.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
sourceSearchPath.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPath.c_str(),
|
||||||
|
"SimpleZoneIW5",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
|
||||||
|
// x64 for now produces invalid zones, don't try to load them yet
|
||||||
|
#ifdef ARCH_x86
|
||||||
|
const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneIW5.ff").string();
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt);
|
||||||
|
REQUIRE(maybeZone);
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
auto pools = dynamic_cast<GameAssetPoolIW5*>(zone->m_pools.get());
|
||||||
|
|
||||||
|
REQUIRE(zone->m_game_id == GameId::IW5);
|
||||||
|
REQUIRE(zone->m_platform == GamePlatform::PC);
|
||||||
|
REQUIRE(zone->m_name == "SimpleZoneIW5");
|
||||||
|
REQUIRE(pools->GetTotalAssetCount() == 1);
|
||||||
|
REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
1
test/SystemTests/Game/T5/Simple/SimpleZone.txt
Normal file
1
test/SystemTests/Game/T5/Simple/SimpleZone.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is a simple zone.
|
||||||
4
test/SystemTests/Game/T5/Simple/SimpleZoneT5.zone
Normal file
4
test/SystemTests/Game/T5/Simple/SimpleZoneT5.zone
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
>game,T5
|
||||||
|
|
||||||
|
rawfile,SimpleZone.txt
|
||||||
|
|
||||||
65
test/SystemTests/Game/T5/SimpleZoneT5.cpp
Normal file
65
test/SystemTests/Game/T5/SimpleZoneT5.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Game/T5/GameAssetPoolT5.h"
|
||||||
|
#include "Linker.h"
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
TEST_CASE("Simple Zone(T5)", "[t5][system][simple]")
|
||||||
|
{
|
||||||
|
const auto assetSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/T5/Simple").string();
|
||||||
|
const auto sourceSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/T5/Simple").string();
|
||||||
|
const auto outputPath = oat::paths::GetTempDirectory("SimpleZoneT5").string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--asset-search-path",
|
||||||
|
assetSearchPath.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
sourceSearchPath.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPath.c_str(),
|
||||||
|
"SimpleZoneT5",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
|
||||||
|
// x64 for now produces invalid zones, don't try to load them yet
|
||||||
|
#ifdef ARCH_x86
|
||||||
|
const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneT5.ff").string();
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt);
|
||||||
|
REQUIRE(maybeZone);
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
auto pools = dynamic_cast<GameAssetPoolT5*>(zone->m_pools.get());
|
||||||
|
|
||||||
|
REQUIRE(zone->m_game_id == GameId::T5);
|
||||||
|
REQUIRE(zone->m_platform == GamePlatform::PC);
|
||||||
|
REQUIRE(zone->m_name == "SimpleZoneT5");
|
||||||
|
REQUIRE(pools->GetTotalAssetCount() == 1);
|
||||||
|
REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
>game,T6
|
||||||
|
|
||||||
|
techniqueset,trivial_floatz_2992w610
|
||||||
|
material,test
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
>game,T6
|
||||||
|
|
||||||
|
ignore,ZoneWithTechsetT6
|
||||||
|
material,test
|
||||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
|||||||
|
>game,T6
|
||||||
|
|
||||||
|
techniqueset,trivial_floatz_2992w610
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://openassettools.dev/schema/material.v1.json",
|
||||||
|
"_game": "t6",
|
||||||
|
"_type": "material",
|
||||||
|
"_version": 1,
|
||||||
|
"cameraRegion": "none",
|
||||||
|
"constants": [],
|
||||||
|
"contents": 1,
|
||||||
|
"gameFlags": [],
|
||||||
|
"layeredSurfaceTypes": 536870912,
|
||||||
|
"sortKey": 4,
|
||||||
|
"stateBits": [
|
||||||
|
{
|
||||||
|
"alphaTest": "disabled",
|
||||||
|
"blendOpAlpha": "disabled",
|
||||||
|
"blendOpRgb": "disabled",
|
||||||
|
"colorWriteAlpha": true,
|
||||||
|
"colorWriteRgb": true,
|
||||||
|
"cullFace": "back",
|
||||||
|
"depthTest": "disabled",
|
||||||
|
"depthWrite": false,
|
||||||
|
"dstBlendAlpha": "zero",
|
||||||
|
"dstBlendRgb": "zero",
|
||||||
|
"polygonOffset": "offset0",
|
||||||
|
"polymodeLine": false,
|
||||||
|
"srcBlendAlpha": "one",
|
||||||
|
"srcBlendRgb": "one"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateBitsEntry": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"stateFlags": 0,
|
||||||
|
"surfaceFlags": 0,
|
||||||
|
"surfaceTypeBits": 0,
|
||||||
|
"techniqueSet": "trivial_floatz_2992w610",
|
||||||
|
"textureAtlas": {
|
||||||
|
"columns": 1,
|
||||||
|
"rows": 1
|
||||||
|
},
|
||||||
|
"textures": []
|
||||||
|
}
|
||||||
130
test/SystemTests/Game/T6/ExtendAndDereferenceT6.cpp
Normal file
130
test/SystemTests/Game/T6/ExtendAndDereferenceT6.cpp
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
This makes sure that when reusing assets from an existing zone, asset dependencies that are references can be overwritten to be non-references.
|
||||||
|
|
||||||
|
In this case:
|
||||||
|
|
||||||
|
- The zone `ZoneWithTechsetT6` contains the techniqueset `trivial_floatz_2992w610`
|
||||||
|
- The zone `ZoneWithMaterialT6` contains the material `test` and with a reference to its techniqueset `,trivial_floatz_2992w610`
|
||||||
|
- The final zone `CombinedZoneT6` is built while loading both of the other fastfile and is expected to contain both the material `test` with a reference to a
|
||||||
|
(actual asset, not a reference) techniqueset `trivial_floatz_2992w610`
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Game/T6/GameAssetPoolT6.h"
|
||||||
|
#include "Linker.h"
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void BuildZoneWithMaterial(const fs::path& testDir, const fs::path& outputPath)
|
||||||
|
{
|
||||||
|
const auto testDirStr = testDir.string();
|
||||||
|
const auto outputPathStr = outputPath.string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--asset-search-path",
|
||||||
|
testDirStr.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
testDirStr.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPathStr.c_str(),
|
||||||
|
"ZoneWithMaterialT6",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildCombinedZone(const fs::path& testDir, const fs::path& outputPath)
|
||||||
|
{
|
||||||
|
const auto testDirStr = testDir.string();
|
||||||
|
const auto outputPathStr = outputPath.string();
|
||||||
|
|
||||||
|
const auto zoneWithTechsetPathStr = (testDir / "ZoneWithTechsetT6.ff").string();
|
||||||
|
const auto zoneWithMaterialPathStr = (outputPath / "ZoneWithMaterialT6.ff").string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--load",
|
||||||
|
zoneWithTechsetPathStr.c_str(),
|
||||||
|
"--load",
|
||||||
|
zoneWithMaterialPathStr.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
testDirStr.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPathStr.c_str(),
|
||||||
|
"CombinedZoneT6",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckCombinedZoneContent(const fs::path& outputPath)
|
||||||
|
{
|
||||||
|
const auto expectedZonePath = (fs::path(outputPath) / "CombinedZoneT6.ff").string();
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt);
|
||||||
|
REQUIRE(maybeZone);
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
auto pools = dynamic_cast<GameAssetPoolT6*>(zone->m_pools.get());
|
||||||
|
|
||||||
|
REQUIRE(zone->m_game_id == GameId::T6);
|
||||||
|
REQUIRE(zone->m_platform == GamePlatform::PC);
|
||||||
|
REQUIRE(zone->m_name == "CombinedZoneT6");
|
||||||
|
REQUIRE(pools->GetTotalAssetCount() == 2);
|
||||||
|
REQUIRE(pools->m_technique_set->GetAsset("trivial_floatz_2992w610"));
|
||||||
|
|
||||||
|
const auto* material = pools->m_material->GetAsset("test");
|
||||||
|
REQUIRE(material);
|
||||||
|
REQUIRE(material->Asset()->techniqueSet);
|
||||||
|
REQUIRE(material->Asset()->techniqueSet->name == "trivial_floatz_2992w610"s);
|
||||||
|
REQUIRE(material->Asset()->techniqueSet->techniques[T6::TECHNIQUE_UNLIT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// x64 for now produces invalid zones, don't try to load them yet
|
||||||
|
#ifdef ARCH_x86
|
||||||
|
TEST_CASE("Extend and dereference(T6)", "[t6][system][simple]")
|
||||||
|
{
|
||||||
|
const auto testDir = oat::paths::GetSystemTestsDirectory() / "Game/T6/ExtendAndDereference";
|
||||||
|
const auto outputPath = oat::paths::GetTempDirectory("ExtendAndDereferenceT6");
|
||||||
|
|
||||||
|
BuildZoneWithMaterial(testDir, outputPath);
|
||||||
|
BuildCombinedZone(testDir, outputPath);
|
||||||
|
CheckCombinedZoneContent(outputPath);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
>game,T6
|
||||||
|
|
||||||
|
material,,Suzanne
|
||||||
|
material,,Suzanne2
|
||||||
|
xmodel,Suzanne1
|
||||||
|
xmodel,Suzanne2
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://openassettools.dev/schema/xmodel.v1.json",
|
||||||
|
"_game": "t6",
|
||||||
|
"_type": "xmodel",
|
||||||
|
"_version": 2,
|
||||||
|
"flags": 2621440,
|
||||||
|
"lightingOriginOffset": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.5
|
||||||
|
},
|
||||||
|
"lightingOriginRange": 0.5,
|
||||||
|
"lods": [
|
||||||
|
{
|
||||||
|
"distance": 11447.6904296875,
|
||||||
|
"file": "model_export/Suzanne1.gltf"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "rigid"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://openassettools.dev/schema/xmodel.v1.json",
|
||||||
|
"_game": "t6",
|
||||||
|
"_type": "xmodel",
|
||||||
|
"_version": 2,
|
||||||
|
"flags": 2621440,
|
||||||
|
"lightingOriginOffset": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0,
|
||||||
|
"z": 0.5
|
||||||
|
},
|
||||||
|
"lightingOriginRange": 0.5,
|
||||||
|
"lods": [
|
||||||
|
{
|
||||||
|
"distance": 11447.6904296875,
|
||||||
|
"file": "model_export/Suzanne2.gltf"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "rigid"
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
>game,T6
|
||||||
|
|
||||||
|
ignore,Ignored
|
||||||
|
xmodel,Suzanne2
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://openassettools.dev/schema/material.v1.json",
|
||||||
|
"_game": "t6",
|
||||||
|
"_type": "material",
|
||||||
|
"_version": 1,
|
||||||
|
"cameraRegion": "none",
|
||||||
|
"constants": [],
|
||||||
|
"contents": 1,
|
||||||
|
"gameFlags": [],
|
||||||
|
"layeredSurfaceTypes": 536870912,
|
||||||
|
"sortKey": 4,
|
||||||
|
"stateBits": [
|
||||||
|
{
|
||||||
|
"alphaTest": "disabled",
|
||||||
|
"blendOpAlpha": "disabled",
|
||||||
|
"blendOpRgb": "disabled",
|
||||||
|
"colorWriteAlpha": true,
|
||||||
|
"colorWriteRgb": true,
|
||||||
|
"cullFace": "back",
|
||||||
|
"depthTest": "disabled",
|
||||||
|
"depthWrite": false,
|
||||||
|
"dstBlendAlpha": "zero",
|
||||||
|
"dstBlendRgb": "zero",
|
||||||
|
"polygonOffset": "offset0",
|
||||||
|
"polymodeLine": false,
|
||||||
|
"srcBlendAlpha": "one",
|
||||||
|
"srcBlendRgb": "one"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateBitsEntry": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"stateFlags": 0,
|
||||||
|
"surfaceFlags": 0,
|
||||||
|
"surfaceTypeBits": 0,
|
||||||
|
"techniqueSet": "trivial_floatz_2992w610",
|
||||||
|
"textureAtlas": {
|
||||||
|
"columns": 1,
|
||||||
|
"rows": 1
|
||||||
|
},
|
||||||
|
"textures": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://openassettools.dev/schema/material.v1.json",
|
||||||
|
"_game": "t6",
|
||||||
|
"_type": "material",
|
||||||
|
"_version": 1,
|
||||||
|
"cameraRegion": "none",
|
||||||
|
"constants": [],
|
||||||
|
"contents": 1,
|
||||||
|
"gameFlags": [],
|
||||||
|
"layeredSurfaceTypes": 536870912,
|
||||||
|
"sortKey": 4,
|
||||||
|
"stateBits": [
|
||||||
|
{
|
||||||
|
"alphaTest": "disabled",
|
||||||
|
"blendOpAlpha": "disabled",
|
||||||
|
"blendOpRgb": "disabled",
|
||||||
|
"colorWriteAlpha": true,
|
||||||
|
"colorWriteRgb": true,
|
||||||
|
"cullFace": "back",
|
||||||
|
"depthTest": "disabled",
|
||||||
|
"depthWrite": false,
|
||||||
|
"dstBlendAlpha": "zero",
|
||||||
|
"dstBlendRgb": "zero",
|
||||||
|
"polygonOffset": "offset0",
|
||||||
|
"polymodeLine": false,
|
||||||
|
"srcBlendAlpha": "one",
|
||||||
|
"srcBlendRgb": "one"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateBitsEntry": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"stateFlags": 0,
|
||||||
|
"surfaceFlags": 0,
|
||||||
|
"surfaceTypeBits": 0,
|
||||||
|
"techniqueSet": "trivial_floatz_2992w610",
|
||||||
|
"textureAtlas": {
|
||||||
|
"columns": 1,
|
||||||
|
"rows": 1
|
||||||
|
},
|
||||||
|
"textures": []
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
techniqueset,trivial_floatz_2992w610
|
||||||
|
137
test/SystemTests/Game/T6/ReuseGlobalAssetPoolsAssetsT6.cpp
Normal file
137
test/SystemTests/Game/T6/ReuseGlobalAssetPoolsAssetsT6.cpp
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
This makes sure that when reusing assets from an existing zone, asset dependencies that are references can be overwritten to be non-references.
|
||||||
|
|
||||||
|
In this case:
|
||||||
|
|
||||||
|
- The zone `ZoneWithTechsetT6` contains the techniqueset `trivial_floatz_2992w610`
|
||||||
|
- The zone `ZoneWithMaterialT6` contains the material `test` and with a reference to its techniqueset `,trivial_floatz_2992w610`
|
||||||
|
- The final zone `CombinedZoneT6` is built while loading both of the other fastfile and is expected to contain both the material `test` with a reference to a
|
||||||
|
(actual asset, not a reference) techniqueset `trivial_floatz_2992w610`
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Game/T6/GameAssetPoolT6.h"
|
||||||
|
#include "Linker.h"
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
#include "Unlinker.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void BuildBaseZone(const fs::path& testDir, const fs::path& outputPath)
|
||||||
|
{
|
||||||
|
const auto testDirStr = testDir.string();
|
||||||
|
const auto assetDirStr = (testDir / "BaseZone").string();
|
||||||
|
const auto outputPathStr = outputPath.string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--add-asset-search-path",
|
||||||
|
assetDirStr.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
testDirStr.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPathStr.c_str(),
|
||||||
|
"BaseZone",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildTestZone(const fs::path& testDir, const fs::path& outputPath)
|
||||||
|
{
|
||||||
|
const auto testDirStr = testDir.string();
|
||||||
|
const auto assetDirStr = (testDir / "TestZone").string();
|
||||||
|
const auto outputPathStr = outputPath.string();
|
||||||
|
|
||||||
|
const auto baseZonePathStr = (outputPath / "BaseZone.ff").string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--load",
|
||||||
|
baseZonePathStr.c_str(),
|
||||||
|
"--add-asset-search-path",
|
||||||
|
assetDirStr.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
testDirStr.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPathStr.c_str(),
|
||||||
|
"TestZone",
|
||||||
|
"TestZone", // build twice to ensure the second build uses a global asset that the first build already used
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckTestZoneContent(const fs::path& outputPath)
|
||||||
|
{
|
||||||
|
const auto expectedZonePathStr = (outputPath / "TestZone.ff").string();
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(expectedZonePathStr, std::nullopt);
|
||||||
|
REQUIRE(maybeZone);
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
auto pools = dynamic_cast<GameAssetPoolT6*>(zone->m_pools.get());
|
||||||
|
|
||||||
|
REQUIRE(zone->m_game_id == GameId::T6);
|
||||||
|
REQUIRE(zone->m_platform == GamePlatform::PC);
|
||||||
|
REQUIRE(zone->m_name == "TestZone");
|
||||||
|
REQUIRE(pools->GetTotalAssetCount() == 3);
|
||||||
|
REQUIRE(pools->m_material->GetAsset("Suzanne2"));
|
||||||
|
REQUIRE(pools->m_technique_set->GetAsset(",trivial_floatz_2992w610"));
|
||||||
|
|
||||||
|
const auto* xmodel = pools->m_xmodel->GetAsset("Suzanne2");
|
||||||
|
REQUIRE(xmodel);
|
||||||
|
REQUIRE(xmodel->Asset()->boneNames);
|
||||||
|
REQUIRE(xmodel->Asset()->numRootBones == 1);
|
||||||
|
REQUIRE(xmodel->Asset()->numBones == 3);
|
||||||
|
REQUIRE(zone->m_script_strings.Value(xmodel->Asset()->boneNames[0]) == "Root2");
|
||||||
|
REQUIRE(zone->m_script_strings.Value(xmodel->Asset()->boneNames[1]) == "EarLeft2");
|
||||||
|
REQUIRE(zone->m_script_strings.Value(xmodel->Asset()->boneNames[2]) == "EarRight2");
|
||||||
|
}
|
||||||
|
|
||||||
|
// x64 for now produces invalid zones, don't try to load them yet
|
||||||
|
#ifdef ARCH_x86
|
||||||
|
TEST_CASE("Reuse assets from global asset pool(T6)", "[t6][system][simple]")
|
||||||
|
{
|
||||||
|
const auto testDir = oat::paths::GetSystemTestsDirectory() / "Game/T6/ReuseGlobalAssetPoolsAssets";
|
||||||
|
const auto outputPath = oat::paths::GetTempDirectory("ReuseGlobalAssetPoolsAssetsT6");
|
||||||
|
|
||||||
|
BuildBaseZone(testDir, outputPath);
|
||||||
|
BuildTestZone(testDir, outputPath);
|
||||||
|
CheckTestZoneContent(outputPath);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace
|
||||||
1
test/SystemTests/Game/T6/Simple/SimpleZone.txt
Normal file
1
test/SystemTests/Game/T6/Simple/SimpleZone.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is a simple zone.
|
||||||
4
test/SystemTests/Game/T6/Simple/SimpleZoneT6.zone
Normal file
4
test/SystemTests/Game/T6/Simple/SimpleZoneT6.zone
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
>game,T6
|
||||||
|
|
||||||
|
rawfile,SimpleZone.txt
|
||||||
|
|
||||||
65
test/SystemTests/Game/T6/SimpleZoneT6.cpp
Normal file
65
test/SystemTests/Game/T6/SimpleZoneT6.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Game/T6/GameAssetPoolT6.h"
|
||||||
|
#include "Linker.h"
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
#include "ZoneLoading.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
TEST_CASE("Simple Zone(T6)", "[t6][system][simple]")
|
||||||
|
{
|
||||||
|
const auto assetSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/T6/Simple").string();
|
||||||
|
const auto sourceSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/T6/Simple").string();
|
||||||
|
const auto outputPath = oat::paths::GetTempDirectory("SimpleZoneT6").string();
|
||||||
|
|
||||||
|
const char* argStrings[]{
|
||||||
|
"SystemTests", // bin
|
||||||
|
"--verbose",
|
||||||
|
"--asset-search-path",
|
||||||
|
assetSearchPath.c_str(),
|
||||||
|
"--source-search-path",
|
||||||
|
sourceSearchPath.c_str(),
|
||||||
|
"--output-folder",
|
||||||
|
outputPath.c_str(),
|
||||||
|
"SimpleZoneT6",
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkerArgs args;
|
||||||
|
|
||||||
|
bool shouldContinue = true;
|
||||||
|
const auto couldParseArgs = args.ParseArgs(std::extent_v<decltype(argStrings)>, argStrings, shouldContinue);
|
||||||
|
|
||||||
|
REQUIRE(couldParseArgs);
|
||||||
|
REQUIRE(shouldContinue);
|
||||||
|
|
||||||
|
const auto linker = Linker::Create(std::move(args));
|
||||||
|
const auto linkerResult = linker->Start();
|
||||||
|
|
||||||
|
REQUIRE(linkerResult);
|
||||||
|
|
||||||
|
// x64 for now produces invalid zones, don't try to load them yet
|
||||||
|
#ifdef ARCH_x86
|
||||||
|
const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneT6.ff").string();
|
||||||
|
auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt);
|
||||||
|
REQUIRE(maybeZone);
|
||||||
|
|
||||||
|
auto zone = std::move(*maybeZone);
|
||||||
|
auto pools = dynamic_cast<GameAssetPoolT6*>(zone->m_pools.get());
|
||||||
|
|
||||||
|
REQUIRE(zone->m_game_id == GameId::T6);
|
||||||
|
REQUIRE(zone->m_platform == GamePlatform::PC);
|
||||||
|
REQUIRE(zone->m_name == "SimpleZoneT6");
|
||||||
|
REQUIRE(pools->GetTotalAssetCount() == 1);
|
||||||
|
REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
15
test/SystemTests/SystemTestsPaths.cpp
Normal file
15
test/SystemTests/SystemTestsPaths.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include "SystemTestsPaths.h"
|
||||||
|
|
||||||
|
#include "OatTestPaths.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace oat::paths
|
||||||
|
{
|
||||||
|
std::filesystem::path GetSystemTestsDirectory()
|
||||||
|
{
|
||||||
|
return GetTestDirectory() / "SystemTests";
|
||||||
|
}
|
||||||
|
} // namespace oat::paths
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user