diff --git a/src/ZoneCode/Game/IW5/XAssets/clipMap_t.txt b/src/ZoneCode/Game/IW5/XAssets/clipMap_t.txt index 64798d62..7b62a24d 100644 --- a/src/ZoneCode/Game/IW5/XAssets/clipMap_t.txt +++ b/src/ZoneCode/Game/IW5/XAssets/clipMap_t.txt @@ -7,6 +7,7 @@ set string name; set name name; set block pInfo XFILE_BLOCK_TEMP; set reusable pInfo; +set action pInfo ReallocClipInfo(ClipInfo, clipMap_t); set count staticModelList numStaticModels; set count nodes numNodes; set count leafs numLeafs; diff --git a/src/ZoneCodeGeneratorLib/Domain/Information/MemberInformation.h b/src/ZoneCodeGeneratorLib/Domain/Information/MemberInformation.h index ee421c35..d0b94ea7 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Information/MemberInformation.h +++ b/src/ZoneCodeGeneratorLib/Domain/Information/MemberInformation.h @@ -4,7 +4,6 @@ #include "Domain/Evaluation/IEvaluation.h" #include "Domain/FastFile/FastFileBlock.h" #include "StructureInformation.h" -#include "Utils/ClassUtils.h" #include @@ -22,6 +21,7 @@ public: bool m_is_leaf; std::unique_ptr m_condition; std::unique_ptr m_alloc_alignment; + std::unique_ptr m_post_load_action; const FastFileBlock* m_fast_file_block; const EnumMember* m_asset_ref; diff --git a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp index 9478ed24..c5ae8ff8 100644 --- a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp @@ -3,6 +3,8 @@ #include "Domain/Computations/MemberComputations.h" #include "Domain/Computations/StructureComputations.h" +#include + RenderingUsedType::RenderingUsedType(const DataDefinition* type, StructureInformation* info) : m_members_loaded(false), m_type(type), @@ -140,26 +142,52 @@ void RenderingContext::CreateUsedTypeCollections() { if (usedType->m_info != nullptr) { - StructureComputations computations(usedType->m_info); + const StructureComputations computations(usedType->m_info); if (usedType->m_info->m_definition == usedType->m_type) m_used_structures.push_back(usedType); - if (computations.IsAsset() && usedType->m_info != m_asset) - m_referenced_assets.push_back(usedType); - - if (!m_has_actions) + if (computations.IsAsset()) { - if ((!computations.IsAsset() || usedType->m_is_context_asset) && usedType->m_non_runtime_reference_exists - && usedType->m_info->m_post_load_action) - { - m_has_actions = true; - } + if (usedType->m_info != m_asset) + m_referenced_assets.push_back(usedType); + else + usedType->m_is_context_asset = true; + } + + if (!m_has_actions && UsedTypeHasActions(usedType)) + { + m_has_actions = true; } } } } +bool RenderingContext::UsedTypeHasActions(const RenderingUsedType* usedType) const +{ + const StructureComputations computations(usedType->m_info); + + if (computations.IsAsset() && !usedType->m_is_context_asset) + return false; + + if (!usedType->m_non_runtime_reference_exists && !usedType->m_is_context_asset) + return false; + + if (usedType->m_info->m_post_load_action) + return true; + + if (std::ranges::any_of(usedType->m_info->m_ordered_members, + [](const auto& member) -> bool + { + return member->m_post_load_action && !MemberComputations(member.get()).ShouldIgnore(); + })) + { + return true; + } + + return false; +} + std::unique_ptr RenderingContext::BuildContext(const IDataRepository* repository, StructureInformation* asset) { auto context = std::make_unique(RenderingContext(repository->GetGameName(), repository->GetAllFastFileBlocks())); diff --git a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h index bedd3b5a..01a28483 100644 --- a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h +++ b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h @@ -36,6 +36,7 @@ class RenderingContext void ScanUsedTypeIfNeeded(const IDataRepository* repository, MemberComputations* computations, RenderingUsedType* usedType); void MakeAsset(const IDataRepository* repository, StructureInformation* asset); void CreateUsedTypeCollections(); + bool UsedTypeHasActions(const RenderingUsedType* usedType) const; public: std::string m_game; diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index ce5c3b5a..a01235ac 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -327,6 +327,12 @@ class ZoneLoadTemplate::Internal final : BaseTemplate LINE("") LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get())) } + + if (member->m_post_load_action) + { + LINE("") + LINE(MakeCustomActionCall(member->m_post_load_action.get())) + } } else { @@ -378,6 +384,12 @@ class ZoneLoadTemplate::Internal final : BaseTemplate LINE("") LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get())) } + + if (member->m_post_load_action) + { + LINE("") + LINE(MakeCustomActionCall(member->m_post_load_action.get())) + } } else if (computations.IsAfterPartialLoad()) { @@ -424,6 +436,12 @@ class ZoneLoadTemplate::Internal final : BaseTemplate LINE("") LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get())) } + + if (member->m_post_load_action) + { + LINE("") + LINE(MakeCustomActionCall(member->m_post_load_action.get())) + } } else if (computations.IsAfterPartialLoad()) { @@ -446,6 +464,12 @@ class ZoneLoadTemplate::Internal final : BaseTemplate LINE("") LINE(MakeCustomActionCall(member->m_type->m_post_load_action.get())) } + + if (member->m_post_load_action) + { + LINE("") + LINE(MakeCustomActionCall(member->m_post_load_action.get())) + } } else { diff --git a/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceAction.cpp b/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceAction.cpp index bc7a9d30..adb30fb8 100644 --- a/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceAction.cpp +++ b/src/ZoneCodeGeneratorLib/Parsing/Commands/Sequence/SequenceAction.cpp @@ -40,6 +40,7 @@ SequenceAction::SequenceAction() void SequenceAction::ProcessMatch(CommandsParserState* state, SequenceResult& result) const { StructureInformation* type; + MemberInformation* member = nullptr; const auto& actionNameToken = result.NextCapture(CAPTURE_ACTION_NAME); // If a typename was specified then try to parse it @@ -53,11 +54,7 @@ void SequenceAction::ProcessMatch(CommandsParserState* state, SequenceResultm_type; - if (type == nullptr) - throw ParsingException(typeNameToken.GetPos(), "Member is not a data type with members."); - } + member = memberChain.back(); } else if (state->GetInUse() != nullptr) { @@ -79,5 +76,12 @@ void SequenceAction::ProcessMatch(CommandsParserState* state, SequenceResultm_post_load_action = std::make_unique(actionNameToken.IdentifierValue(), std::move(parameterTypes)); + auto action = std::make_unique(actionNameToken.IdentifierValue(), std::move(parameterTypes)); + + if (member != nullptr) + member->m_post_load_action = std::move(action); + else if (type != nullptr) + type->m_post_load_action = std::move(action); + else + throw ParsingException(actionNameToken.GetPos(), "Unknown type"); } diff --git a/src/ZoneLoading/Game/IW5/XAssets/clipmap_t/clipmap_t_actions.cpp b/src/ZoneLoading/Game/IW5/XAssets/clipmap_t/clipmap_t_actions.cpp new file mode 100644 index 00000000..59237320 --- /dev/null +++ b/src/ZoneLoading/Game/IW5/XAssets/clipmap_t/clipmap_t_actions.cpp @@ -0,0 +1,17 @@ +#include "clipmap_t_actions.h" + +#include +#include + +using namespace IW5; + +Actions_clipMap_t::Actions_clipMap_t(Zone* zone) + : AssetLoadingActions(zone) +{ +} + +void Actions_clipMap_t::ReallocClipInfo(ClipInfo* clipInfo, clipMap_t* clipMap) const +{ + clipMap->pInfo = static_cast(m_zone->GetMemory()->Alloc(sizeof(ClipInfo))); + memcpy(clipMap->pInfo, clipInfo, sizeof(ClipInfo)); +} diff --git a/src/ZoneLoading/Game/IW5/XAssets/clipmap_t/clipmap_t_actions.h b/src/ZoneLoading/Game/IW5/XAssets/clipmap_t/clipmap_t_actions.h new file mode 100644 index 00000000..90c11ac3 --- /dev/null +++ b/src/ZoneLoading/Game/IW5/XAssets/clipmap_t/clipmap_t_actions.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Game/IW5/IW5.h" +#include "Loading/AssetLoadingActions.h" + +namespace IW5 +{ + class Actions_clipMap_t final : public AssetLoadingActions + { + public: + explicit Actions_clipMap_t(Zone* zone); + + void ReallocClipInfo(ClipInfo* clipInfo, clipMap_t* clipMap) const; + }; +} // namespace IW5 diff --git a/test/ZoneCodeGeneratorLibTests/Parsing/Commands/Sequence/SequenceActionTests.cpp b/test/ZoneCodeGeneratorLibTests/Parsing/Commands/Sequence/SequenceActionTests.cpp index 2c89f3a0..ef9aeea2 100644 --- a/test/ZoneCodeGeneratorLibTests/Parsing/Commands/Sequence/SequenceActionTests.cpp +++ b/test/ZoneCodeGeneratorLibTests/Parsing/Commands/Sequence/SequenceActionTests.cpp @@ -17,11 +17,12 @@ namespace test::parsing::commands::sequence::sequence_action std::unique_ptr m_state; std::unique_ptr> m_lexer; - StructDefinition* m_test_struct_raw; + StructDefinition* m_test_struct_t; StructureInformation* m_test_struct; - StructDefinition* m_test_struct2_raw; - StructureInformation* m_test_struct2; + StructDefinition* m_container_struct_t; + StructureInformation* m_container_struct; + MemberInformation* m_container_struct_child; StructDefinition* m_arg_struct_raw; StructureInformation* m_arg_struct; @@ -37,10 +38,12 @@ namespace test::parsing::commands::sequence::sequence_action private: void RetrieveInformationPointers() { - m_test_struct = m_repository->GetInformationFor(m_test_struct_raw); + m_test_struct = m_repository->GetInformationFor(m_test_struct_t); REQUIRE(m_test_struct != nullptr); - m_test_struct2 = m_repository->GetInformationFor(m_test_struct2_raw); - REQUIRE(m_test_struct2 != nullptr); + m_container_struct = m_repository->GetInformationFor(m_container_struct_t); + REQUIRE(m_container_struct != nullptr); + m_container_struct_child = m_container_struct->m_ordered_members[0].get(); + REQUIRE(m_container_struct_child != nullptr); m_arg_struct = m_repository->GetInformationFor(m_arg_struct_raw); REQUIRE(m_arg_struct != nullptr); m_arg_struct2 = m_repository->GetInformationFor(m_arg_struct2_raw); @@ -61,12 +64,12 @@ namespace test::parsing::commands::sequence::sequence_action { auto def = std::make_unique("", "test_struct_t", 8); def->m_members.emplace_back(std::make_shared("m_test", std::make_unique(BaseTypeDefinition::BOOL))); - m_test_struct_raw = def.get(); + m_test_struct_t = def.get(); m_repository->Add(std::move(def)); def = std::make_unique("", "container_struct_t", 8); - def->m_members.emplace_back(std::make_shared("m_child", std::make_unique(m_test_struct_raw))); - m_test_struct2_raw = def.get(); + def->m_members.emplace_back(std::make_shared("m_child", std::make_unique(m_test_struct_t))); + m_container_struct_t = def.get(); m_repository->Add(std::move(def)); def = std::make_unique("", "arg_t", 8); @@ -91,10 +94,10 @@ namespace test::parsing::commands::sequence::sequence_action CommandsSequenceTestsHelper() : m_repository(std::make_unique()), m_state(std::make_unique(m_repository.get())), - m_test_struct_raw(nullptr), + m_test_struct_t(nullptr), m_test_struct(nullptr), - m_test_struct2_raw(nullptr), - m_test_struct2(nullptr), + m_container_struct_t(nullptr), + m_container_struct(nullptr), m_arg_struct_raw(nullptr), m_arg_struct(nullptr), m_arg_struct2_raw(nullptr), @@ -339,9 +342,11 @@ namespace test::parsing::commands::sequence::sequence_action REQUIRE(result); REQUIRE(helper.m_consumed_token_count == 10); - REQUIRE(helper.m_test_struct->m_post_load_action); - REQUIRE(helper.m_test_struct->m_post_load_action->m_action_name == "TestMethod"); - REQUIRE(helper.m_test_struct->m_post_load_action->m_parameter_types.empty()); + REQUIRE(helper.m_test_struct->m_post_load_action == nullptr); + + REQUIRE(helper.m_container_struct_child->m_post_load_action); + REQUIRE(helper.m_container_struct_child->m_post_load_action->m_action_name == "TestMethod"); + REQUIRE(helper.m_container_struct_child->m_post_load_action->m_parameter_types.empty()); } TEST_CASE("SequenceAction: Ensure can parse action directive with type from member and in use", "[parsing][sequence]") @@ -358,15 +363,17 @@ namespace test::parsing::commands::sequence::sequence_action CommandsParserValue::Character(pos, ';'), CommandsParserValue::EndOfFile(pos), }); - helper.m_state->SetInUse(helper.m_test_struct2); + helper.m_state->SetInUse(helper.m_container_struct); auto result = helper.PerformTest(); REQUIRE(result); REQUIRE(helper.m_consumed_token_count == 7); - REQUIRE(helper.m_test_struct->m_post_load_action); - REQUIRE(helper.m_test_struct->m_post_load_action->m_action_name == "TestMethod"); - REQUIRE(helper.m_test_struct->m_post_load_action->m_parameter_types.empty()); + REQUIRE(helper.m_test_struct->m_post_load_action == nullptr); + + REQUIRE(helper.m_container_struct_child->m_post_load_action); + REQUIRE(helper.m_container_struct_child->m_post_load_action->m_action_name == "TestMethod"); + REQUIRE(helper.m_container_struct_child->m_post_load_action->m_parameter_types.empty()); } TEST_CASE("SequenceAction: Ensure can use different struct even though something is used", "[parsing][sequence]") @@ -392,30 +399,10 @@ namespace test::parsing::commands::sequence::sequence_action REQUIRE(result); REQUIRE(helper.m_consumed_token_count == 10); - REQUIRE(helper.m_test_struct->m_post_load_action); - REQUIRE(helper.m_test_struct->m_post_load_action->m_action_name == "TestMethod"); - REQUIRE(helper.m_test_struct->m_post_load_action->m_parameter_types.empty()); - } - - TEST_CASE("SequenceAction: Ensure member must be type with members", "[parsing][sequence]") - { - CommandsSequenceTestsHelper helper; - const TokenPos pos; - helper.Tokens({ - CommandsParserValue::Identifier(pos, new std::string("set")), - CommandsParserValue::Identifier(pos, new std::string("action")), - CommandsParserValue::Identifier(pos, new std::string("test_struct_t")), - CommandsParserValue::Character(pos, ':'), - CommandsParserValue::Character(pos, ':'), - CommandsParserValue::Identifier(pos, new std::string("m_test")), - CommandsParserValue::Identifier(pos, new std::string("TestMethod")), - CommandsParserValue::Character(pos, '('), - CommandsParserValue::Character(pos, ')'), - CommandsParserValue::Character(pos, ';'), - CommandsParserValue::EndOfFile(pos), - }); - - REQUIRE_THROWS_AS(helper.PerformTest(), ParsingException); REQUIRE(helper.m_test_struct->m_post_load_action == nullptr); + + REQUIRE(helper.m_container_struct_child->m_post_load_action); + REQUIRE(helper.m_container_struct_child->m_post_load_action->m_action_name == "TestMethod"); + REQUIRE(helper.m_container_struct_child->m_post_load_action->m_parameter_types.empty()); } } // namespace test::parsing::commands::sequence::sequence_action