diff --git a/src/Linker/Linker.cpp b/src/Linker/Linker.cpp index fbe52b00..c82a4fda 100644 --- a/src/Linker/Linker.cpp +++ b/src/Linker/Linker.cpp @@ -157,10 +157,6 @@ class LinkerImpl final : public Linker return nullptr; } - // If no type was defined explicitly make it fastfile - if (zoneDefinition->m_type == ProjectType::NONE) - zoneDefinition->m_type = ProjectType::FASTFILE; - if (!IncludeAdditionalZoneDefinitions(targetName, *zoneDefinition, sourceSearchPath)) return nullptr; @@ -338,29 +334,11 @@ class LinkerImpl final : public Linker if (!zoneDefinition) return false; - auto result = true; - if (zoneDefinition->m_type != ProjectType::NONE) - { - const auto& gameName = GameId_Names[static_cast(zoneDefinition->m_game)]; - auto assetSearchPaths = m_search_paths.GetAssetSearchPathsForProject(gameName, projectName); - auto gdtSearchPaths = m_search_paths.GetGdtSearchPathsForProject(gameName, projectName); + const auto& gameName = GameId_Names[static_cast(zoneDefinition->m_game)]; + auto assetSearchPaths = m_search_paths.GetAssetSearchPathsForProject(gameName, projectName); + auto gdtSearchPaths = m_search_paths.GetGdtSearchPathsForProject(gameName, projectName); - switch (zoneDefinition->m_type) - { - case ProjectType::FASTFILE: - result = BuildFastFile(projectName, targetName, *zoneDefinition, assetSearchPaths, gdtSearchPaths, sourceSearchPaths); - break; - - case ProjectType::IPAK: - result = BuildIPak(projectName, *zoneDefinition, assetSearchPaths); - break; - - default: - assert(false); - result = false; - break; - } - } + auto result = BuildFastFile(projectName, targetName, *zoneDefinition, assetSearchPaths, gdtSearchPaths, sourceSearchPaths); m_search_paths.UnloadProjectSpecificSearchPaths(); diff --git a/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp b/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp index cb99bd30..3d6d4c46 100644 --- a/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp +++ b/src/ZoneCommon/Parsing/ZoneDefinition/Sequence/SequenceZoneDefinitionMetaData.cpp @@ -3,6 +3,7 @@ #include "Parsing/ZoneDefinition/Matcher/ZoneDefinitionMatcherFactory.h" #include "Utils/StringUtils.h" +#include #include #include @@ -13,6 +14,9 @@ namespace constexpr auto METADATA_NAME = "name"; constexpr auto METADATA_TYPE = "type"; + constexpr auto METADATA_IPAK = "ipak"; + constexpr auto METADATA_IWD = "iwd"; + std::optional GetGameByName(const std::string& gameName) { auto upperGameName = gameName; @@ -27,6 +31,21 @@ namespace return std::nullopt; } + enum class ProjectType : std::uint8_t + { + NONE, + FASTFILE, + IPAK, + + COUNT + }; + constexpr const char* ProjectType_Names[]{ + "none", + "fastfile", + "ipak", + }; + static_assert(std::extent_v == static_cast(ProjectType::COUNT)); + std::optional GetProjectTypeByName(const std::string& projectTypeName) { auto lowerProjectTypeName = projectTypeName; @@ -54,16 +73,9 @@ SequenceZoneDefinitionMetaData::SequenceZoneDefinitionMetaData() }); } -void SequenceZoneDefinitionMetaData::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult& result) const +namespace { - const auto& keyToken = result.NextCapture(CAPTURE_KEY); - auto key = keyToken.FieldValue(); - const auto& valueToken = result.NextCapture(CAPTURE_VALUE); - const auto& value = valueToken.FieldValue(); - - utils::MakeStringLowerCase(key); - - if (key == METADATA_GAME) + void ProcessMetaDataGame(ZoneDefinitionParserState* state, const ZoneDefinitionParserValue& valueToken, const std::string& value) { const auto game = GetGameByName(value); if (!game) @@ -75,6 +87,52 @@ void SequenceZoneDefinitionMetaData::ProcessMatch(ZoneDefinitionParserState* sta state->SetGame(*game); } + + void ProcessMetaDataType(ZoneDefinitionParserState* state, const ZoneDefinitionParserValue& keyToken, const ZoneDefinitionParserValue& valueToken) + { + const auto projectType = GetProjectTypeByName(valueToken.FieldValue()); + if (!projectType) + throw ParsingException(valueToken.GetPos(), "Unknown project type name"); + + // TODO: Remove deprecated type + + std::string deprecationSuggestedAction; + if (*projectType == ProjectType::IPAK) + { + deprecationSuggestedAction = "Use \">ipak,name_of_ipak\" instead."; + state->StartIPak(state->m_definition->m_name); + } + else if (*projectType == ProjectType::FASTFILE) + { + deprecationSuggestedAction = "A fastfile will always be built when appropriate assets have been added."; + } + else + { + deprecationSuggestedAction = "It now has no effect."; + } + + const auto keyPos = keyToken.GetPos(); + std::cerr << std::format("Warning: {} L{}: Zone definition \">type,{}\" is deprecated and should be removed. {}\n", + keyPos.m_filename.get(), + keyPos.m_line, + keyToken.FieldValue(), + deprecationSuggestedAction); + } +} // namespace + +void SequenceZoneDefinitionMetaData::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult& result) const +{ + const auto& keyToken = result.NextCapture(CAPTURE_KEY); + auto key = keyToken.FieldValue(); + const auto& valueToken = result.NextCapture(CAPTURE_VALUE); + const auto& value = valueToken.FieldValue(); + + utils::MakeStringLowerCase(key); + + if (key == METADATA_GAME) + { + ProcessMetaDataGame(state, valueToken, value); + } else if (key == METADATA_GDT) { state->m_definition->m_gdts.emplace_back(value); @@ -85,9 +143,21 @@ void SequenceZoneDefinitionMetaData::ProcessMatch(ZoneDefinitionParserState* sta } else if (key == METADATA_TYPE) { - const auto projectType = GetProjectTypeByName(value); - if (!projectType) - throw ParsingException(valueToken.GetPos(), "Unknown project type name"); + ProcessMetaDataType(state, keyToken, valueToken); + } + else if (key == METADATA_IPAK) + { + if (!value.empty()) + state->StartIPak(value); + else + throw ParsingException(valueToken.GetPos(), "IPak must have a name"); + } + else if (key == METADATA_IWD) + { + if (!value.empty()) + state->StartIwd(value); + else + throw ParsingException(valueToken.GetPos(), "IWD must have a name"); } else { diff --git a/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.cpp b/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.cpp index beabf448..17cd9df0 100644 --- a/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.cpp +++ b/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.cpp @@ -1,5 +1,7 @@ #include "ZoneDefinitionParserState.h" +#include + ZoneDefinitionParserState::ZoneDefinitionParserState(std::string targetName) : m_asset_name_resolver(nullptr), m_definition(std::make_unique()) @@ -12,3 +14,50 @@ void ZoneDefinitionParserState::SetGame(const GameId game) m_definition->m_game = game; m_asset_name_resolver = IAssetNameResolver::GetResolverForGame(game); } + +namespace +{ + void AddCurrentObjContainerToDefinitionIfNecessary(ZoneDefinition& zoneDefinition, std::optional& maybeObjContainer) + { + if (!maybeObjContainer) + return; + + maybeObjContainer->m_asset_end = zoneDefinition.m_assets.size(); + zoneDefinition.m_obj_containers.emplace_back(std::move(*maybeObjContainer)); + maybeObjContainer = std::nullopt; + } + + ZoneDefinitionObjContainer DefineNewObjContainer(const ZoneDefinition& zoneDefinition, std::string name, const ZoneDefinitionObjContainerType type) + { + return ZoneDefinitionObjContainer(std::move(name), type, zoneDefinition.m_assets.size()); + } + + void SortObjContainer(ZoneDefinition& zoneDefinition) + { + std::ranges::sort(zoneDefinition.m_obj_containers, + [](const ZoneDefinitionObjContainer& obj0, const ZoneDefinitionObjContainer& obj1) + { + return obj0.m_asset_start < obj1.m_asset_start; + }); + } +} // namespace + +void ZoneDefinitionParserState::StartIPak(std::string ipakName) +{ + AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_ipak); + m_current_ipak = DefineNewObjContainer(*m_definition, std::move(ipakName), ZoneDefinitionObjContainerType::IPAK); +} + +void ZoneDefinitionParserState::StartIwd(std::string iwdName) +{ + AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_iwd); + m_current_iwd = DefineNewObjContainer(*m_definition, std::move(iwdName), ZoneDefinitionObjContainerType::IWD); +} + +void ZoneDefinitionParserState::Finalize() +{ + AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_ipak); + AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_iwd); + + SortObjContainer(*m_definition); +} diff --git a/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.h b/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.h index 8135636e..75c3fb0b 100644 --- a/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.h +++ b/src/ZoneCommon/Parsing/ZoneDefinition/ZoneDefinitionParserState.h @@ -4,6 +4,7 @@ #include "Zone/Definition/ZoneDefinition.h" #include +#include class ZoneDefinitionParserState { @@ -12,6 +13,15 @@ public: void SetGame(GameId game); + void StartIPak(std::string ipakName); + void StartIwd(std::string iwdName); + + void Finalize(); + const IAssetNameResolver* m_asset_name_resolver; + + std::optional m_current_ipak; + std::optional m_current_iwd; + std::unique_ptr m_definition; }; diff --git a/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp b/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp index ee36f59b..a4a90f4c 100644 --- a/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp +++ b/src/ZoneCommon/Zone/Definition/ZoneDefinition.cpp @@ -1,5 +1,13 @@ #include "ZoneDefinition.h" +ZoneDefinitionObjContainer::ZoneDefinitionObjContainer(std::string name, const ZoneDefinitionObjContainerType type, const unsigned start) + : m_name(std::move(name)), + m_type(type), + m_asset_start(start), + m_asset_end(0u) +{ +} + ZoneDefinitionAsset::ZoneDefinitionAsset(const asset_type_t type, std::string name, const bool isReference) : m_asset_type(type), m_asset_name(std::move(name)), @@ -21,8 +29,7 @@ void ZoneDefinitionProperties::Include(const ZoneDefinitionProperties& otherProp } ZoneDefinition::ZoneDefinition() - : m_type(ProjectType::NONE), - m_game(GameId::COUNT) + : m_game(GameId::COUNT) { } diff --git a/src/ZoneCommon/Zone/Definition/ZoneDefinition.h b/src/ZoneCommon/Zone/Definition/ZoneDefinition.h index 515013d1..d0c06946 100644 --- a/src/ZoneCommon/Zone/Definition/ZoneDefinition.h +++ b/src/ZoneCommon/Zone/Definition/ZoneDefinition.h @@ -4,25 +4,35 @@ #include "Zone/AssetList/AssetList.h" #include "Zone/ZoneTypes.h" +#include #include #include #include -enum class ProjectType +enum class ZoneDefinitionObjContainerType : uint8_t { - NONE, - FASTFILE, - IPAK, - - COUNT + IWD, + IPAK }; -static constexpr const char* ProjectType_Names[]{ - "none", - "fastfile", - "ipak", +class ZoneDefinitionObjContainer +{ +public: + std::string m_name; + ZoneDefinitionObjContainerType m_type; + + /** + * \brief The first asset (inclusive) to include in the obj container. + */ + unsigned m_asset_start; + + /** + * \brief The last asset (exclusive) to include in the obj container. + */ + unsigned m_asset_end; + + ZoneDefinitionObjContainer(std::string name, ZoneDefinitionObjContainerType type, unsigned start); }; -static_assert(std::extent_v == static_cast(ProjectType::COUNT)); class ZoneDefinitionAsset { @@ -54,7 +64,6 @@ public: void Include(const ZoneDefinition& definitionToInclude); std::string m_name; - ProjectType m_type; GameId m_game; ZoneDefinitionProperties m_properties; std::vector m_includes; @@ -63,4 +72,5 @@ public: std::vector m_targets_to_build; std::vector m_gdts; std::vector m_assets; + std::vector m_obj_containers; };