#include "SequenceZoneDefinitionMetaData.h" #include "Utils/Logging/Log.h" #include "Utils/StringUtils.h" #include "Zone/Definition/Parsing/Matcher/ZoneDefinitionMatcherFactory.h" #include #include #include namespace { constexpr auto METADATA_GAME = "game"; constexpr auto METADATA_GDT = "gdt"; 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; utils::MakeStringUpperCase(upperGameName); for (auto i = 0u; i < static_cast(GameId::COUNT); i++) { if (upperGameName == GameId_Names[i]) return static_cast(i); } 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; utils::MakeStringLowerCase(lowerProjectTypeName); for (auto i = 0u; i < static_cast(ProjectType::COUNT); i++) { if (lowerProjectTypeName == ProjectType_Names[i]) return static_cast(i); } return std::nullopt; } } // namespace SequenceZoneDefinitionMetaData::SequenceZoneDefinitionMetaData() { const ZoneDefinitionMatcherFactory create(this); AddMatchers({ create.Char('>'), create.Field().Capture(CAPTURE_KEY), create.Char(','), create.Field().Capture(CAPTURE_VALUE), }); } namespace { void ProcessMetaDataGame(ZoneDefinitionParserState* state, const ZoneDefinitionParserValue& valueToken, const std::string& value) { const auto game = GetGameByName(value); if (!game) throw ParsingException(valueToken.GetPos(), "Unknown game name"); const auto previousGame = state->m_definition->m_game; if (previousGame != GameId::COUNT && previousGame != *game) throw ParsingException(valueToken.GetPos(), std::format("Game was previously defined as: {}", GameId_Names[static_cast(previousGame)])); 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(); con::error("Warning: {} L{}: Zone definition \">type,{}\" is deprecated and should be removed. {}", 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); } else if (key == METADATA_NAME) { state->m_definition->m_name = value; } else if (key == METADATA_TYPE) { 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 { state->m_definition->m_properties.AddProperty(key, value); } }