From 083365191bd5f586edd850e0bd6a0190de782ab1 Mon Sep 17 00:00:00 2001 From: hop311 Date: Mon, 15 Apr 2024 00:13:46 +0100 Subject: Rework GFX::Actor Attachments and Animations --- src/openvic-simulation/dataloader/Dataloader.cpp | 3 +- src/openvic-simulation/interface/GFXObject.cpp | 104 +++++++++++++++------ src/openvic-simulation/interface/GFXObject.hpp | 42 ++++----- src/openvic-simulation/interface/UI.cpp | 6 ++ src/openvic-simulation/interface/UI.hpp | 5 +- .../types/IdentifierRegistry.hpp | 21 +++++ 6 files changed, 127 insertions(+), 54 deletions(-) diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index e13bc23..f99417f 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -280,8 +280,7 @@ bool Dataloader::_load_interface_files(UIManager& ui_manager) const { return ui_manager.load_gfx_file(parse_defines(file).get_file_node()); } ); - ui_manager.lock_sprites(); - ui_manager.lock_fonts(); + ui_manager.lock_gfx_registries(); /* Hard-coded GUI file names, might be replaced with a dynamic system but everything should still be loaded on startup. */ static const std::vector gui_files { diff --git a/src/openvic-simulation/interface/GFXObject.cpp b/src/openvic-simulation/interface/GFXObject.cpp index d873db1..67abc4d 100644 --- a/src/openvic-simulation/interface/GFXObject.cpp +++ b/src/openvic-simulation/interface/GFXObject.cpp @@ -101,44 +101,92 @@ node_callback_t Object::expect_objects(length_callback_t length_callback, callba ); } -Actor::Attachment::Attachment() : node {}, attach_id { 0 } {} +Actor::Attachment::Attachment(std::string_view new_actor_name, std::string_view new_attach_node, attach_id_t new_attach_id) + : actor_name { new_actor_name }, attach_node { new_attach_node }, attach_id { new_attach_id } {} -bool Actor::Attachment::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) { - bool ret = Named::_fill_key_map(key_map); - ret &= add_key_map_entries(key_map, - "node", ONE_EXACTLY, expect_string(assign_variable_callback_string(node)), - "attachId", ONE_EXACTLY, expect_uint(assign_variable_callback(attach_id)) - ); - return ret; -} +Actor::Animation::Animation(std::string_view new_file, fixed_point_t new_scroll_time) + : file { new_file }, scroll_time { new_scroll_time } {} -Actor::Animation::Animation() : file {}, default_time { 0 } {} +Actor::Actor() : model_file {}, scale { 1 }, idle_animation {}, move_animation {}, attack_animation {} {} -bool Actor::Animation::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) { - bool ret = Named::_fill_key_map(key_map); - ret &= add_key_map_entries(key_map, - "file", ONE_EXACTLY, expect_string(assign_variable_callback_string(file)), - "defaultAnimationTime", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(default_time)) - ); - return ret; -} +bool Actor::_set_animation(std::string_view name, std::string_view file, fixed_point_t scroll_time) { + std::optional* animation = nullptr; + + if (name == "idle") { + animation = &idle_animation; + } else if (name == "move") { + animation = &move_animation; + } else if (name == "attack") { + animation = &attack_animation; + } else { + Logger::error( + "Unknown animation type \"", name, "\" for actor ", get_name(), " (with file ", file, " and scroll time ", + scroll_time, ")" + ); + return false; + } + + if (animation->has_value()) { + Logger::error( + "Duplicate ", name, " animation for actor ", get_name(), ": ", file, " with scroll time ", + scroll_time, " (already set to ", (*animation)->file, " with scroll time ", (*animation)->scroll_time, ")" + ); + return false; + } -Actor::Actor() : model_file {}, idle_animation_file {}, move_animation_file {}, attack_animation_file {}, scale { 1 } {} + /* Don't set static/non-moving animation, to avoid needing an AnimationPlayer for the generated Godot Skeleton3D. */ + static constexpr std::string_view null_animation = "static.xsm"; + if (file.ends_with(null_animation)) { + return true; + } + + animation->emplace(Animation { file, scroll_time }); + return true; +} bool Actor::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) { bool ret = Object::_fill_key_map(key_map); + ret &= add_key_map_entries(key_map, "actorfile", ONE_EXACTLY, expect_string(assign_variable_callback_string(model_file)), - "idle", ZERO_OR_ONE, expect_string(assign_variable_callback_string(idle_animation_file)), - "move", ZERO_OR_ONE, expect_string(assign_variable_callback_string(move_animation_file)), - "attack", ZERO_OR_ONE, expect_string(assign_variable_callback_string(attack_animation_file)), "scale", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(scale)), - "attach", ZERO_OR_MORE, Attachment::_expect_value([this](Attachment&& attachment) -> bool { - return attachments.add_item(std::move(attachment)); - }), - "animation", ZERO_OR_MORE, Animation::_expect_value([this](Animation&& animation) -> bool { - return animations.add_item(std::move(animation)); - }) + + "attach", ZERO_OR_MORE, [this](ast::NodeCPtr node) -> bool { + std::string_view actor_name {}, attach_node {}; + Attachment::attach_id_t attach_id = 0; + + if (!expect_dictionary_keys( + "name", ONE_EXACTLY, expect_string(assign_variable_callback(actor_name)), + "node", ONE_EXACTLY, expect_string(assign_variable_callback(attach_node)), + "attachId", ONE_EXACTLY, expect_uint(assign_variable_callback(attach_id)) + )(node)) { + Logger::error("Failed to load attachment for actor ", get_name()); + return false; + } + + attachments.push_back({ actor_name, attach_node, attach_id }); + return true; + }, + + "idle", ZERO_OR_ONE, expect_string(std::bind(&Actor::_set_animation, this, "idle", std::placeholders::_1, 0)), + "move", ZERO_OR_ONE, expect_string(std::bind(&Actor::_set_animation, this, "move", std::placeholders::_1, 0)), + "attack", ZERO_OR_ONE, expect_string(std::bind(&Actor::_set_animation, this, "attack", std::placeholders::_1, 0)), + "animation", ZERO_OR_MORE, [this](ast::NodeCPtr node) -> bool { + std::string_view name {}, file {}; + fixed_point_t scroll_time = 0; + + if (!expect_dictionary_keys( + "name", ONE_EXACTLY, expect_string(assign_variable_callback(name)), + "file", ONE_EXACTLY, expect_string(assign_variable_callback(file)), + "defaultAnimationTime", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(scroll_time)) + )(node)) { + Logger::error("Failed to load animation for actor ", get_name()); + return false; + } + + return _set_animation(name, file, scroll_time); + } ); + return ret; } diff --git a/src/openvic-simulation/interface/GFXObject.hpp b/src/openvic-simulation/interface/GFXObject.hpp index 840e4a9..db15096 100644 --- a/src/openvic-simulation/interface/GFXObject.hpp +++ b/src/openvic-simulation/interface/GFXObject.hpp @@ -24,48 +24,44 @@ namespace OpenVic::GFX { friend std::unique_ptr std::make_unique(); public: - class Attachment : public Named<> { - friend class LoadBase; + class Attachment { + friend class Actor; - private: - std::string PROPERTY(node); - int32_t PROPERTY(attach_id); + public: + using attach_id_t = uint32_t; - protected: - Attachment(); + private: + std::string PROPERTY(actor_name); + std::string PROPERTY(attach_node); + attach_id_t PROPERTY(attach_id); - bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; + Attachment(std::string_view new_actor_name, std::string_view new_attach_node, attach_id_t new_attach_id); public: Attachment(Attachment&&) = default; - virtual ~Attachment() = default; }; - class Animation : public Named<> { - friend class LoadBase; + class Animation { + friend class Actor; std::string PROPERTY(file); - fixed_point_t PROPERTY(default_time); + fixed_point_t PROPERTY(scroll_time); - protected: - Animation(); - - bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; + Animation(std::string_view new_file, fixed_point_t new_scroll_time); public: Animation(Animation&&) = default; - virtual ~Animation() = default; }; private: - std::string PROPERTY(model_file); - std::string PROPERTY(idle_animation_file); - std::string PROPERTY(move_animation_file); - std::string PROPERTY(attack_animation_file); fixed_point_t PROPERTY(scale); + std::string PROPERTY(model_file); + std::optional PROPERTY(idle_animation); + std::optional PROPERTY(move_animation); + std::optional PROPERTY(attack_animation); + std::vector PROPERTY(attachments); - NamedRegistry IDENTIFIER_REGISTRY(attachment); - NamedRegistry IDENTIFIER_REGISTRY(animation); + bool _set_animation(std::string_view name, std::string_view file, fixed_point_t scroll_time); protected: Actor(); diff --git a/src/openvic-simulation/interface/UI.cpp b/src/openvic-simulation/interface/UI.cpp index 479948d..ea871de 100644 --- a/src/openvic-simulation/interface/UI.cpp +++ b/src/openvic-simulation/interface/UI.cpp @@ -55,6 +55,12 @@ NodeCallback auto UIManager::_load_fonts(std::string_view font_key) { ); } +void UIManager::lock_gfx_registries() { + lock_sprites(); + lock_fonts(); + lock_objects(); +} + bool UIManager::load_gfx_file(ast::NodeCPtr root) { return expect_dictionary_keys( "spriteTypes", ZERO_OR_ONE, Sprite::expect_sprites( diff --git a/src/openvic-simulation/interface/UI.hpp b/src/openvic-simulation/interface/UI.hpp index ada540a..9aec96c 100644 --- a/src/openvic-simulation/interface/UI.hpp +++ b/src/openvic-simulation/interface/UI.hpp @@ -7,10 +7,11 @@ namespace OpenVic { class UIManager { NamedInstanceRegistry IDENTIFIER_REGISTRY(sprite); - NamedInstanceRegistry IDENTIFIER_REGISTRY(scene); IdentifierRegistry IDENTIFIER_REGISTRY(font); NamedInstanceRegistry IDENTIFIER_REGISTRY(object); + NamedInstanceRegistry IDENTIFIER_REGISTRY(scene); + bool _load_font(ast::NodeCPtr node); NodeTools::NodeCallback auto _load_fonts(std::string_view font_key); @@ -20,6 +21,8 @@ namespace OpenVic { uint32_t height ); + void lock_gfx_registries(); + bool load_gfx_file(ast::NodeCPtr root); bool load_gui_file(std::string_view scene_name, ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index c1fef9d..533273a 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -269,6 +269,23 @@ namespace OpenVic { } \ return nullptr; \ } \ + template T> \ + requires requires(external_value_type const& value) { \ + { value.get_type() } -> std::same_as; \ + { T::get_type_static() } -> std::same_as; \ + } \ + constexpr T CONST* get_cast_item_by_identifier(std::string_view identifier) CONST { \ + external_value_type CONST* item = get_item_by_identifier(identifier); \ + if (item != nullptr) { \ + if (item->get_type() == T::get_type_static()) { \ + return reinterpret_cast(item); \ + } \ + Logger::error( \ + "Invalid type for item \"", identifier, "\": ", item->get_type(), " (expected ", T::get_type_static(), ")" \ + ); \ + } \ + return nullptr; \ + } \ constexpr external_value_type CONST* get_item_by_index(std::size_t index) CONST { \ if (index < items.size()) { \ return std::addressof(ValueInfo::get_external_value(ItemInfo::get_value(items[index]))); \ @@ -565,6 +582,10 @@ private: constexpr decltype(registry)::external_value_type const_kw* get_##singular##_by_identifier(std::string_view identifier) const_kw { \ return registry.get_item_by_identifier(identifier); \ } \ + template T> \ + constexpr T const_kw* get_cast_##singular##_by_identifier(std::string_view identifier) const_kw { \ + return registry.get_cast_item_by_identifier(identifier); \ + } \ constexpr decltype(registry)::external_value_type const_kw* get_##singular##_by_index(std::size_t index) const_kw { \ return index >= index_offset ? registry.get_item_by_index(index - index_offset) : nullptr; \ } \ -- cgit v1.2.3-56-ga3b1 From 8708e62d96fe298e1135538298172b6283bc56fb Mon Sep 17 00:00:00 2001 From: hop311 Date: Mon, 15 Apr 2024 00:24:29 +0100 Subject: Dynamically load default GraphicalCultureType --- src/openvic-simulation/pop/Culture.cpp | 30 ++++++++++++++++-------------- src/openvic-simulation/pop/Culture.hpp | 7 +++++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/openvic-simulation/pop/Culture.cpp b/src/openvic-simulation/pop/Culture.cpp index 9466e9f..18ed3d8 100644 --- a/src/openvic-simulation/pop/Culture.cpp +++ b/src/openvic-simulation/pop/Culture.cpp @@ -22,6 +22,8 @@ Culture::Culture( first_names { std::move(new_first_names) }, last_names { std::move(new_last_names) }, radicalism { new_radicalism }, primary_country { new_primary_country } {} +CultureManager::CultureManager() : default_graphical_culture_type { nullptr } {} + bool CultureManager::add_graphical_culture_type(std::string_view identifier) { if (identifier.empty()) { Logger::error("Invalid culture group identifier - empty!"); @@ -78,17 +80,26 @@ bool CultureManager::load_graphical_culture_type_file(ast::NodeCPtr root) { graphical_culture_types, expect_identifier(std::bind_front(&CultureManager::add_graphical_culture_type, this)) )(root); + lock_graphical_culture_types(); + + if (graphical_culture_types_empty()) { + Logger::error("Cannot set default graphical culture type - none loaded!"); + return false; + } + + /* Last defined graphical culture type is used as default. */ + default_graphical_culture_type = &get_graphical_culture_types().back(); + return ret; } bool CultureManager::_load_culture_group( - CountryManager const& country_manager, size_t& total_expected_cultures, - GraphicalCultureType const* default_unit_graphical_culture_type, std::string_view culture_group_key, + CountryManager const& country_manager, size_t& total_expected_cultures, std::string_view culture_group_key, ast::NodeCPtr culture_group_node ) { std::string_view leader {}; - GraphicalCultureType const* unit_graphical_culture_type = default_unit_graphical_culture_type; + GraphicalCultureType const* unit_graphical_culture_type = default_graphical_culture_type; bool is_overseas = true; Country const* union_country = nullptr; @@ -152,21 +163,12 @@ bool CultureManager::load_culture_file(CountryManager const& country_manager, as return false; } - static constexpr std::string_view default_unit_graphical_culture_type_identifier = "Generic"; - GraphicalCultureType const* const default_unit_graphical_culture_type = - get_graphical_culture_type_by_identifier(default_unit_graphical_culture_type_identifier); - if (default_unit_graphical_culture_type == nullptr) { - Logger::error("Failed to find default unit graphical culture type: ", default_unit_graphical_culture_type_identifier); - } - size_t total_expected_cultures = 0; bool ret = expect_dictionary_reserve_length(culture_groups, - [this, &country_manager, default_unit_graphical_culture_type, &total_expected_cultures]( + [this, &country_manager, &total_expected_cultures]( std::string_view key, ast::NodeCPtr value ) -> bool { - return _load_culture_group( - country_manager, total_expected_cultures, default_unit_graphical_culture_type, key, value - ); + return _load_culture_group(country_manager, total_expected_cultures, key, value); } )(root); lock_culture_groups(); diff --git a/src/openvic-simulation/pop/Culture.hpp b/src/openvic-simulation/pop/Culture.hpp index 8807123..72ea3ee 100644 --- a/src/openvic-simulation/pop/Culture.hpp +++ b/src/openvic-simulation/pop/Culture.hpp @@ -61,10 +61,11 @@ namespace OpenVic { IdentifierRegistry IDENTIFIER_REGISTRY(culture_group); IdentifierRegistry IDENTIFIER_REGISTRY(culture); + GraphicalCultureType const* PROPERTY(default_graphical_culture_type); + bool _load_culture_group( CountryManager const& country_manager, size_t& total_expected_cultures, - GraphicalCultureType const* default_unit_graphical_culture_type, std::string_view culture_group_key, - ast::NodeCPtr culture_group_node + std::string_view culture_group_key, ast::NodeCPtr culture_group_node ); bool _load_culture( CountryManager const& country_manager, CultureGroup const& culture_group, std::string_view culture_key, @@ -72,6 +73,8 @@ namespace OpenVic { ); public: + CultureManager(); + bool add_graphical_culture_type(std::string_view identifier); bool add_culture_group( -- cgit v1.2.3-56-ga3b1 From b358fc0d4250178fbb44fc6b00cf4e39aa870064 Mon Sep 17 00:00:00 2001 From: hop311 Date: Mon, 15 Apr 2024 00:24:37 +0100 Subject: Add default country unit colours --- src/openvic-simulation/country/Country.cpp | 15 ++++++++------- src/openvic-simulation/country/Country.hpp | 3 +-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/openvic-simulation/country/Country.cpp b/src/openvic-simulation/country/Country.cpp index 5ec4aee..0fdeb60 100644 --- a/src/openvic-simulation/country/Country.cpp +++ b/src/openvic-simulation/country/Country.cpp @@ -43,14 +43,12 @@ Country::Country( alternative_colours { std::move(new_alternative_colours) }, primary_unit_colour { new_primary_unit_colour }, secondary_unit_colour { new_secondary_unit_colour }, - tertiary_unit_colour { new_tertiary_unit_colour } - {} + tertiary_unit_colour { new_tertiary_unit_colour } {} bool CountryManager::add_country( std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture, IdentifierRegistry&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, - Country::government_colour_map_t&& alternative_colours, - colour_t primary_unit_colour, colour_t secondary_unit_colour, colour_t tertiary_unit_colour + Country::government_colour_map_t&& alternative_colours ) { if (identifier.empty()) { Logger::error("Invalid country identifier - empty!"); @@ -67,9 +65,13 @@ bool CountryManager::add_country( return false; } + static constexpr colour_t default_colour = colour_t::fill_as(colour_t::max_value); + return countries.add_item({ identifier, colour, *graphical_culture, std::move(parties), std::move(unit_names), dynamic_tag, - std::move(alternative_colours), primary_unit_colour, secondary_unit_colour, tertiary_unit_colour + std::move(alternative_colours), + /* Default to country colour for the chest and grey for the others. Update later if necessary. */ + colour, default_colour, default_colour }); } @@ -205,8 +207,7 @@ bool CountryManager::load_country_data_file( )(root); ret &= add_country( - name, colour, graphical_culture, std::move(parties), std::move(unit_names), is_dynamic, - std::move(alternative_colours), colour_t::null(), colour_t::null(), colour_t::null() + name, colour, graphical_culture, std::move(parties), std::move(unit_names), is_dynamic, std::move(alternative_colours) ); return ret; } diff --git a/src/openvic-simulation/country/Country.hpp b/src/openvic-simulation/country/Country.hpp index ea8f732..1d960c2 100644 --- a/src/openvic-simulation/country/Country.hpp +++ b/src/openvic-simulation/country/Country.hpp @@ -85,8 +85,7 @@ namespace OpenVic { bool add_country( std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture, IdentifierRegistry&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, - Country::government_colour_map_t&& alternative_colours, - colour_t primary_unit_colour, colour_t secondary_unit_colour, colour_t tertiary_unit_colour + Country::government_colour_map_t&& alternative_colours ); bool load_country_colours(ast::NodeCPtr root); -- cgit v1.2.3-56-ga3b1