From 70f0564af84f5bda8a3b73abec4612de8545d5d9 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 19 Oct 2026 15:04:32 +0200 Subject: [PATCH] feat: add possibility to only include structs in zcg for certain variants --- .../Domain/GameVariant.cpp | 5 +- src/ZoneCodeGeneratorLib/Domain/GameVariant.h | 3 +- .../Information/StructureInformation.cpp | 5 ++ .../Domain/Information/StructureInformation.h | 8 ++ .../Generating/CodeGenerator.cpp | 4 + .../Generating/Templates/ZoneLoadTemplate.cpp | 3 + .../Generating/Templates/ZoneMarkTemplate.cpp | 3 + .../Templates/ZoneWriteTemplate.cpp | 3 + .../Parsing/Commands/Impl/CommandsParser.cpp | 2 + .../Commands/Impl/CommandsParserState.cpp | 3 +- .../Commands/Sequence/SequenceSetVariant.cpp | 77 +++++++++++++++++++ .../Commands/Sequence/SequenceSetVariant.h | 12 +++ 12 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.cpp create mode 100644 src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.h diff --git a/src/ZoneCodeGeneratorLib/Domain/GameVariant.cpp b/src/ZoneCodeGeneratorLib/Domain/GameVariant.cpp index c35787f1..e0030219 100644 --- a/src/ZoneCodeGeneratorLib/Domain/GameVariant.cpp +++ b/src/ZoneCodeGeneratorLib/Domain/GameVariant.cpp @@ -1,7 +1,8 @@ #include "GameVariant.h" -GameVariant::GameVariant(std::string name, const WordSize wordSize, const std::endian endianness) - : m_name(std::move(name)), +GameVariant::GameVariant(const unsigned index, std::string name, const WordSize wordSize, const std::endian endianness) + : m_index(index), + m_name(std::move(name)), m_word_size(wordSize), m_endianness(endianness) { diff --git a/src/ZoneCodeGeneratorLib/Domain/GameVariant.h b/src/ZoneCodeGeneratorLib/Domain/GameVariant.h index d7ed6323..00bb51b1 100644 --- a/src/ZoneCodeGeneratorLib/Domain/GameVariant.h +++ b/src/ZoneCodeGeneratorLib/Domain/GameVariant.h @@ -8,8 +8,9 @@ class GameVariant { public: - GameVariant(std::string name, WordSize wordSize, std::endian endianness); + GameVariant(unsigned index, std::string name, WordSize wordSize, std::endian endianness); + unsigned m_index; std::string m_name; WordSize m_word_size; std::endian m_endianness; diff --git a/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.cpp b/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.cpp index fd0f0883..0de5fc2c 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.cpp +++ b/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.cpp @@ -16,3 +16,8 @@ StructureInformation::StructureInformation(DefinitionWithMembers* definition, Ty m_block(nullptr) { } + +bool StructureInformation::IsIncludedForVariant(const unsigned variantIndex) const +{ + return m_variants.empty() || m_variants.contains(variantIndex); +} diff --git a/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.h b/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.h index d7bb0658..75678303 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.h +++ b/src/ZoneCodeGeneratorLib/Domain/Information/StructureInformation.h @@ -8,6 +8,7 @@ #include "TypeInformation.h" #include +#include #include class MemberInformation; @@ -17,10 +18,17 @@ class StructureInformation public: StructureInformation(DefinitionWithMembers* definition, TypeInformation* typeInfo); + [[nodiscard]] bool IsIncludedForVariant(unsigned variantIndex) const; + DefinitionWithMembers* m_definition; TypeInformation* m_type_info; std::string m_asset_name; + /** + * All variants this structure should be included in. If empty, it should be included in all variants. + */ + std::unordered_set m_variants; + std::unique_ptr m_alloc_alignment; std::vector m_usages; std::vector> m_ordered_members; diff --git a/src/ZoneCodeGeneratorLib/Generating/CodeGenerator.cpp b/src/ZoneCodeGeneratorLib/Generating/CodeGenerator.cpp index 83f2cc54..795fb53e 100644 --- a/src/ZoneCodeGeneratorLib/Generating/CodeGenerator.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/CodeGenerator.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace fs = std::filesystem; @@ -195,6 +196,9 @@ bool CodeGenerator::GenerateCode(const IDataRepository* repository) { for (auto* asset : assets) { + if (!asset->IsIncludedForVariant(variant->m_index)) + continue; + auto context = std::make_unique(repository, asset, variant); const auto result = GenerateCodeOncePerAsset(*context, foundTemplate->second.get()); LogDirtyCheckResult( diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index cbcbb16f..ca3cc61a 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -33,6 +33,9 @@ namespace for (const auto* asset : m_env.m_all_assets) { + if (!asset->IsIncludedForVariant(m_env.m_variant->m_index)) + continue; + LINEF("#include \"Game/{0}/XAssets/{1}/{1}_{2}_{3}_load_db.h\"", m_env.m_game, Lower(asset->m_definition->m_name), diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp index bff28f97..b99f4f28 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp @@ -33,6 +33,9 @@ namespace for (const auto* asset : m_env.m_all_assets) { + if (!asset->IsIncludedForVariant(m_env.m_variant->m_index)) + continue; + LINEF("#include \"Game/{0}/XAssets/{1}/{1}_{2}_{3}_mark_db.h\"", m_env.m_game, Lower(asset->m_definition->m_name), diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 90addf80..57487bd9 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -33,6 +33,9 @@ namespace for (const auto* asset : m_env.m_all_assets) { + if (!asset->IsIncludedForVariant(m_env.m_variant->m_index)) + continue; + LINEF("#include \"Game/{0}/XAssets/{1}/{1}_{2}_{3}_write_db.h\"", m_env.m_game, Lower(asset->m_definition->m_name), diff --git a/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParser.cpp b/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParser.cpp index c228adf7..9f53c5c8 100644 --- a/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParser.cpp +++ b/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParser.cpp @@ -14,6 +14,7 @@ #include "Parsing/Commands/Sequence/SequenceReusable.h" #include "Parsing/Commands/Sequence/SequenceScriptString.h" #include "Parsing/Commands/Sequence/SequenceSetBlock.h" +#include "Parsing/Commands/Sequence/SequenceSetVariant.h" #include "Parsing/Commands/Sequence/SequenceString.h" #include "Parsing/Commands/Sequence/SequenceUse.h" #include "Parsing/Commands/Sequence/SequenceVariant.h" @@ -41,6 +42,7 @@ const std::vector& CommandsParser::GetTestsForState new SequenceReusable(), new SequenceScriptString(), new SequenceSetBlock(), + new SequenceSetVariant(), new SequenceString(), new SequenceUse(), new SequenceVariant(), diff --git a/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParserState.cpp b/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParserState.cpp index c5914a38..9228e7a6 100644 --- a/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParserState.cpp +++ b/src/ZoneCodeGeneratorLib/Parsing/Commands/Impl/CommandsParserState.cpp @@ -76,7 +76,8 @@ void CommandsParserState::AddBlock(std::unique_ptr block) const void CommandsParserState::AddGameVariant(std::string variantName, const WordSize wordSize, const std::endian endianness) const { - m_repository->AddGameVariant(std::make_unique(std::move(variantName), wordSize, endianness)); + m_repository->AddGameVariant( + std::make_unique(static_cast(m_repository->GetGameVariants().size()), std::move(variantName), wordSize, endianness)); } void CommandsParserState::SetGame(std::string gameName) const diff --git a/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.cpp b/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.cpp new file mode 100644 index 00000000..c000999c --- /dev/null +++ b/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.cpp @@ -0,0 +1,77 @@ +#include "SequenceSetVariant.h" + +#include "Parsing/Commands/Matcher/CommandsCommonMatchers.h" +#include "Parsing/Commands/Matcher/CommandsMatcherFactory.h" + +namespace +{ + constexpr auto CAPTURE_START = 1; + constexpr auto CAPTURE_TYPE_OR_VARIANT = 2; + constexpr auto CAPTURE_VARIANT = 3; + + std::optional GetVariantIndexForName(const IDataRepository& repository, const std::string& name) + { + for (const auto* variant : repository.GetGameVariants()) + { + if (utils::StringEqualsIgnoreCase(variant->m_name, name)) + return variant->m_index; + } + + return std::nullopt; + } +} // namespace + +SequenceSetVariant::SequenceSetVariant() +{ + const CommandsMatcherFactory create(this); + + AddLabeledMatchers(CommandsCommonMatchers::Typename(this), CommandsCommonMatchers::LABEL_TYPENAME); + AddMatchers({ + create.Keyword("set").Capture(CAPTURE_START), + create.Keyword("variant"), + create.Label(CommandsCommonMatchers::LABEL_TYPENAME).Capture(CAPTURE_TYPE_OR_VARIANT), + create.OptionalLoop(create.Identifier().Capture(CAPTURE_VARIANT)), + create.Char(';'), + }); +} + +void SequenceSetVariant::ProcessMatch(CommandsParserState* state, SequenceResult& result) const +{ + const auto& typeOrVariantToken = result.NextCapture(CAPTURE_TYPE_OR_VARIANT); + const auto& typeOrVariantValue = typeOrVariantToken.TypeNameValue(); + const auto maybeTypeOrVariantAsVariantIndex = GetVariantIndexForName(*state->GetRepository(), typeOrVariantValue); + + StructureInformation* information; + std::vector memberChain; + if (state->GetTypenameAndMembersFromTypename(typeOrVariantValue, information, memberChain)) + { + if (maybeTypeOrVariantAsVariantIndex) + throw ParsingException(typeOrVariantToken.GetPos(), "Expression is ambiguous, could both be a variant name or a type."); + + if (!memberChain.empty()) + { + information = memberChain.back()->m_type; + if (information == nullptr) + throw ParsingException(typeOrVariantToken.GetPos(), "Specified type must be a structure."); + } + } + else + { + information = state->GetInUse(); + if (information == nullptr) + throw ParsingException(result.NextCapture(CAPTURE_START).GetPos(), "No type is used. Therefore one needs to be specified directly."); + } + + if (maybeTypeOrVariantAsVariantIndex.has_value()) + information->m_variants.emplace(*maybeTypeOrVariantAsVariantIndex); + + while (result.HasNextCapture(CAPTURE_VARIANT)) + { + const auto& variantToken = result.NextCapture(CAPTURE_VARIANT); + const auto maybeVariant = GetVariantIndexForName(*state->GetRepository(), variantToken.TypeNameValue()); + if (!maybeVariant) + throw ParsingException(variantToken.GetPos(), "No variant with this name."); + + information->m_variants.emplace(*maybeVariant); + } +} diff --git a/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.h b/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.h new file mode 100644 index 00000000..c94f63ea --- /dev/null +++ b/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceSetVariant.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Parsing/Commands/Impl/CommandsParser.h" + +class SequenceSetVariant final : public CommandsParser::sequence_t +{ +public: + SequenceSetVariant(); + +protected: + void ProcessMatch(CommandsParserState* state, SequenceResult& result) const override; +};