diff --git a/src/Linker/AssetLoading/AssetLoadingContext.cpp b/src/Linker/AssetLoading/AssetLoadingContext.cpp new file mode 100644 index 00000000..048a2f2b --- /dev/null +++ b/src/Linker/AssetLoading/AssetLoadingContext.cpp @@ -0,0 +1,12 @@ +#include "AssetLoadingContext.h" + +AssetLoadingContext::AssetLoadingContext() + : m_asset_search_path(nullptr) +{ +} + +AssetLoadingContext::AssetLoadingContext(std::string zoneName, ISearchPath* assetSearchPath) + : m_asset_search_path(assetSearchPath), + m_zone_name(std::move(zoneName)) +{ +} diff --git a/src/Linker/AssetLoading/AssetLoadingContext.h b/src/Linker/AssetLoading/AssetLoadingContext.h new file mode 100644 index 00000000..4517d0c7 --- /dev/null +++ b/src/Linker/AssetLoading/AssetLoadingContext.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include + +#include "SearchPath/ISearchPath.h" +#include "Obj/Gdt/Gdt.h" + +class AssetLoadingContext +{ +public: + ISearchPath* m_asset_search_path; + std::string m_zone_name; + std::string m_game_name; + std::vector> m_gdt_files; + + AssetLoadingContext(); + AssetLoadingContext(std::string zoneName, ISearchPath* assetSearchPath); +}; diff --git a/src/Linker/AssetLoading/IAssetLoader.h b/src/Linker/AssetLoading/IAssetLoader.h new file mode 100644 index 00000000..de984911 --- /dev/null +++ b/src/Linker/AssetLoading/IAssetLoader.h @@ -0,0 +1,20 @@ +#pragma once +#include + +#include "Utils/ClassUtils.h" +#include "AssetLoadingContext.h" +#include "Zone/Zone.h" + +class IAssetLoader +{ +public: + IAssetLoader() = default; + virtual ~IAssetLoader() = default; + IAssetLoader(const IAssetLoader& other) = default; + IAssetLoader(IAssetLoader&& other) noexcept = default; + IAssetLoader& operator=(const IAssetLoader& other) = default; + IAssetLoader& operator=(IAssetLoader&& other) noexcept = default; + + _NODISCARD virtual bool SupportsGame(const std::string& gameName) const = 0; + _NODISCARD virtual std::unique_ptr CreateZoneForDefinition(AssetLoadingContext& context) const = 0; +}; diff --git a/src/Linker/Game/IW4/AssetLoaderIW4.cpp b/src/Linker/Game/IW4/AssetLoaderIW4.cpp new file mode 100644 index 00000000..caa62088 --- /dev/null +++ b/src/Linker/Game/IW4/AssetLoaderIW4.cpp @@ -0,0 +1,22 @@ +#include "AssetLoaderIW4.h" + +#include "Game/IW4/GameIW4.h" +#include "Game/IW4/GameAssetPoolIW4.h" + +using namespace IW4; + +bool AssetLoader::SupportsGame(const std::string& gameName) const +{ + return gameName == g_GameIW4.GetShortName(); +} + +std::unique_ptr AssetLoader::CreateZoneForDefinition(AssetLoadingContext& context) const +{ + auto zone = std::make_unique(context.m_zone_name, 0, &g_GameIW4); + zone->m_pools = std::make_unique(zone.get(), zone->m_priority); + + for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++) + zone->m_pools->InitPoolDynamic(assetType); + + return zone; +} diff --git a/src/Linker/Game/IW4/AssetLoaderIW4.h b/src/Linker/Game/IW4/AssetLoaderIW4.h new file mode 100644 index 00000000..580a453e --- /dev/null +++ b/src/Linker/Game/IW4/AssetLoaderIW4.h @@ -0,0 +1,12 @@ +#pragma once +#include "AssetLoading/IAssetLoader.h" + +namespace IW4 +{ + class AssetLoader final : public IAssetLoader + { + public: + _NODISCARD bool SupportsGame(const std::string& gameName) const override; + _NODISCARD std::unique_ptr CreateZoneForDefinition(AssetLoadingContext& context) const override; + }; +} diff --git a/src/Linker/Game/T6/AssetLoaderT6.cpp b/src/Linker/Game/T6/AssetLoaderT6.cpp new file mode 100644 index 00000000..1f6769ac --- /dev/null +++ b/src/Linker/Game/T6/AssetLoaderT6.cpp @@ -0,0 +1,23 @@ +#include "AssetLoaderT6.h" + +#include "Game/T6/T6.h" +#include "Game/T6/GameT6.h" +#include "Game/T6/GameAssetPoolT6.h" + +using namespace T6; + +bool AssetLoader::SupportsGame(const std::string& gameName) const +{ + return gameName == g_GameT6.GetShortName(); +} + +std::unique_ptr AssetLoader::CreateZoneForDefinition(AssetLoadingContext& context) const +{ + auto zone = std::make_unique(context.m_zone_name, 0, &g_GameT6); + zone->m_pools = std::make_unique(zone.get(), zone->m_priority); + + for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++) + zone->m_pools->InitPoolDynamic(assetType); + + return zone; +} diff --git a/src/Linker/Game/T6/AssetLoaderT6.h b/src/Linker/Game/T6/AssetLoaderT6.h new file mode 100644 index 00000000..2d45343a --- /dev/null +++ b/src/Linker/Game/T6/AssetLoaderT6.h @@ -0,0 +1,12 @@ +#pragma once +#include "AssetLoading/IAssetLoader.h" + +namespace T6 +{ + class AssetLoader final : public IAssetLoader + { + public: + _NODISCARD bool SupportsGame(const std::string& gameName) const override; + _NODISCARD std::unique_ptr CreateZoneForDefinition(AssetLoadingContext& context) const override; + }; +} diff --git a/src/Linker/Linker.cpp b/src/Linker/Linker.cpp index ab726b69..03513fb6 100644 --- a/src/Linker/Linker.cpp +++ b/src/Linker/Linker.cpp @@ -15,6 +15,10 @@ #include "SearchPath/SearchPathFilesystem.h" #include "ObjContainer/IWD/IWD.h" #include "LinkerArgs.h" +#include "AssetLoading/AssetLoadingContext.h" +#include "AssetLoading/IAssetLoader.h" +#include "Game/IW4/AssetLoaderIW4.h" +#include "Game/T6/AssetLoaderT6.h" #include "Utils/ObjFileStream.h" #include "Zone/AssetList/AssetList.h" @@ -23,8 +27,17 @@ namespace fs = std::filesystem; +const IAssetLoader* const ASSET_LOADERS[] +{ + new IW4::AssetLoader(), + new T6::AssetLoader() +}; + class Linker::Impl { + static constexpr const char* METADATA_GAME = "game"; + static constexpr const char* METADATA_GDT = "gdt"; + LinkerArgs m_args; std::vector> m_loaded_zone_search_paths; SearchPaths m_asset_search_paths; @@ -356,10 +369,91 @@ class Linker::Impl return true; } - std::unique_ptr CreateZoneForDefinition(const std::string& zoneName, ZoneDefinition& zoneDefinition) + static bool GetGameNameFromZoneDefinition(std::string& gameName, const std::string& zoneName, const ZoneDefinition& zoneDefinition) { + auto firstGameEntry = true; + const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata.equal_range(METADATA_GAME); + for (auto i = rangeBegin; i != rangeEnd; ++i) + { + if (firstGameEntry) + { + gameName = i->second; + firstGameEntry = false; + } + else + { + if (gameName != i->second) + { + std::cout << "Conflicting game names in zone \"" << zoneName << "\": " << gameName << " != " << i->second << std::endl; + return false; + } + } + } + + if (firstGameEntry) + { + std::cout << "No game name was specified for zone \"" << zoneName << "\"" << std::endl; + return false; + } + + return true; + } + + static bool LoadGdtFilesFromZoneDefinition(std::vector>& gdtList, const std::string& zoneName, const ZoneDefinition& zoneDefinition, ISearchPath* gdtSearchPath) + { + const auto [rangeBegin, rangeEnd] = zoneDefinition.m_metadata.equal_range(METADATA_GDT); + for (auto i = rangeBegin; i != rangeEnd; ++i) + { + const auto gdtFile = gdtSearchPath->Open(i->second + ".gdt"); + if(!gdtFile) + { + std::cout << "Failed to open file for gdt \"" << i->second << "\"" << std::endl; + return false; + } + + GdtReader gdtReader(*gdtFile); + auto gdt = std::make_unique(); + if(!gdtReader.Read(*gdt)) + { + std::cout << "Failed to read gdt file \"" << i->second << "\"" << std::endl; + return false; + } + + gdtList.emplace_back(std::move(gdt)); + } + + return true; + } + + std::unique_ptr CreateZoneForDefinition(const std::string& zoneName, ZoneDefinition& zoneDefinition, ISearchPath* assetSearchPath, ISearchPath* gdtSearchPath) const + { + auto context = std::make_unique(zoneName, assetSearchPath); + if (!GetGameNameFromZoneDefinition(context->m_game_name, zoneName, zoneDefinition)) + return nullptr; + if (!LoadGdtFilesFromZoneDefinition(context->m_gdt_files, zoneName, zoneDefinition, gdtSearchPath)) + return nullptr; + + for(const auto* assetLoader : ASSET_LOADERS) + { + if(assetLoader->SupportsGame(context->m_game_name)) + return assetLoader->CreateZoneForDefinition(*context); + } + return nullptr; } + + bool WriteZoneToFile(Zone* zone) + { + fs::path zoneFilePath(m_args.GetOutputFolderPathForZone(zone->m_name)); + zoneFilePath.append(zone->m_name + ".ff"); + + std::ifstream stream(zoneFilePath); + if (!stream.is_open()) + return false; + + stream.close(); + return true; + } bool BuildZone(const std::string& zoneName) { @@ -374,7 +468,10 @@ class Linker::Impl return false; } - const auto zone = CreateZoneForDefinition(zoneName, *zoneDefinition); + const auto zone = CreateZoneForDefinition(zoneName, *zoneDefinition, &assetSearchPaths, &gdtSearchPaths); + auto result = zone != nullptr; + if (zone) + result = WriteZoneToFile(zone.get()); for(const auto& loadedSearchPath : m_loaded_zone_search_paths) { @@ -382,7 +479,7 @@ class Linker::Impl } m_loaded_zone_search_paths.clear(); - return true; + return result; } public: diff --git a/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp b/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp index 291054ae..03856caf 100644 --- a/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp +++ b/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp @@ -20,5 +20,5 @@ SequenceZoneDefinitionMetaData::SequenceZoneDefinitionMetaData() void SequenceZoneDefinitionMetaData::ProcessMatch(ZoneDefinition* state, SequenceResult& result) const { - state->m_metadata[result.NextCapture(CAPTURE_KEY).IdentifierValue()] = result.NextCapture(CAPTURE_VALUE).IdentifierValue(); + state->m_metadata.insert(std::make_pair(result.NextCapture(CAPTURE_KEY).IdentifierValue(), result.NextCapture(CAPTURE_VALUE).IdentifierValue())); } diff --git a/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp b/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp index 6954652e..db21dd07 100644 --- a/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp +++ b/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp @@ -16,10 +16,7 @@ void ZoneDefinition::Include(ZoneDefinition& definitionToInclude) { for(const auto& [key, value] : definitionToInclude.m_metadata) { - if(m_metadata.find(key) == m_metadata.end()) - { - m_metadata.emplace(std::make_pair(key, value)); - } + m_metadata.emplace(std::make_pair(key, value)); } for(const auto& ignore : definitionToInclude.m_ignores) diff --git a/src/ZoneCommon/Zone/Definition/ZoneDefinition.h b/src/ZoneCommon/Zone/Definition/ZoneDefinition.h index 61bffa09..63c00121 100644 --- a/src/ZoneCommon/Zone/Definition/ZoneDefinition.h +++ b/src/ZoneCommon/Zone/Definition/ZoneDefinition.h @@ -17,7 +17,7 @@ public: class ZoneDefinition { public: - std::unordered_map m_metadata; + std::unordered_multimap m_metadata; std::vector m_includes; std::vector m_ignores; std::vector m_assets;