From eed478f288ad3bc6254bb0c25ca6daa7aaaf6dcf Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sun, 17 Nov 2019 11:14:52 +0700 Subject: [PATCH] return spine events and commands parsing --- headers/enduro2d/high/components/commands.hpp | 65 +- headers/enduro2d/high/components/events.hpp | 65 +- .../enduro2d/high/components/spine_player.hpp | 99 ++- samples/bin/library/prefabs/coin_prefab.json | 10 + .../bin/library/prefabs/dragon_prefab.json | 10 + .../bin/library/prefabs/raptor_prefab.json | 36 + samples/bin/library/prefabs/spine_prefab.json | 4 +- .../scripts/emmy/components/spine_player.lua | 17 +- samples/sources/sample_06/sample_06.cpp | 6 +- scripts/cloc_all.sh | 2 + scripts/cloc_samples.sh | 4 +- scripts/cloc_untests.sh | 4 +- .../components/spine_player_binds.cpp | 27 +- .../enduro2d/high/components/spine_player.cpp | 620 +++++++++++++++++- sources/enduro2d/high/starter.cpp | 5 + .../enduro2d/high/systems/script_system.cpp | 2 +- .../enduro2d/high/systems/spine_system.cpp | 2 +- 17 files changed, 857 insertions(+), 121 deletions(-) diff --git a/headers/enduro2d/high/components/commands.hpp b/headers/enduro2d/high/components/commands.hpp index 5dbdb0d4..d0394d18 100644 --- a/headers/enduro2d/high/components/commands.hpp +++ b/headers/enduro2d/high/components/commands.hpp @@ -15,23 +15,14 @@ namespace e2d public: commands() = default; - [[nodiscard]] - typename vector::const_iterator - begin() const noexcept; - - [[nodiscard]] - typename vector::const_iterator - cbegin() const noexcept; - - [[nodiscard]] - typename vector::const_iterator - end() const noexcept; - - [[nodiscard]] - typename vector::const_iterator - cend() const noexcept; - commands& add(C command); + + commands& set(vector&& commands) noexcept; + commands& set(const vector& commands); + + [[nodiscard]] vector& get() noexcept; + [[nodiscard]] const vector& get() const noexcept; + commands& clear() noexcept; [[nodiscard]] bool empty() const noexcept; [[nodiscard]] std::size_t size() const noexcept; @@ -42,32 +33,34 @@ namespace e2d namespace e2d { - template < typename C > - typename vector::const_iterator commands::begin() const noexcept { - return commands_.begin(); - } - - template < typename C > - typename vector::const_iterator commands::cbegin() const noexcept { - return commands_.cbegin(); - } - - template < typename C > - typename vector::const_iterator commands::end() const noexcept { - return commands_.end(); - } - - template < typename C > - typename vector::const_iterator commands::cend() const noexcept { - return commands_.cend(); - } - template < typename C > commands& commands::add(C command) { commands_.push_back(std::move(command)); return *this; } + template < typename C > + commands& commands::set(vector&& commands) noexcept { + commands_ = std::move(commands); + return *this; + } + + template < typename C > + commands& commands::set(const vector& commands) { + commands_ = commands; + return *this; + } + + template < typename C > + vector& commands::get() noexcept { + return commands_; + } + + template < typename C > + const vector& commands::get() const noexcept { + return commands_; + } + template < typename C > commands& commands::clear() noexcept { commands_.clear(); diff --git a/headers/enduro2d/high/components/events.hpp b/headers/enduro2d/high/components/events.hpp index 60acc1a8..32d8aff2 100644 --- a/headers/enduro2d/high/components/events.hpp +++ b/headers/enduro2d/high/components/events.hpp @@ -15,23 +15,14 @@ namespace e2d public: events() = default; - [[nodiscard]] - typename vector::const_iterator - begin() const noexcept; - - [[nodiscard]] - typename vector::const_iterator - cbegin() const noexcept; - - [[nodiscard]] - typename vector::const_iterator - end() const noexcept; - - [[nodiscard]] - typename vector::const_iterator - cend() const noexcept; - events& add(E event); + + events& set(vector&& events) noexcept; + events& set(const vector& events); + + [[nodiscard]] vector& get() noexcept; + [[nodiscard]] const vector& get() const noexcept; + events& clear() noexcept; [[nodiscard]] bool empty() const noexcept; [[nodiscard]] std::size_t size() const noexcept; @@ -42,32 +33,34 @@ namespace e2d namespace e2d { - template < typename E > - typename vector::const_iterator events::begin() const noexcept { - return events_.begin(); - } - - template < typename E > - typename vector::const_iterator events::cbegin() const noexcept { - return events_.cbegin(); - } - - template < typename E > - typename vector::const_iterator events::end() const noexcept { - return events_.end(); - } - - template < typename E > - typename vector::const_iterator events::cend() const noexcept { - return events_.cend(); - } - template < typename E > events& events::add(E event) { events_.push_back(std::move(event)); return *this; } + template < typename E > + events& events::set(vector&& events) noexcept { + events_ = std::move(events); + return *this; + } + + template < typename E > + events& events::set(const vector& events) { + events_ = events; + return *this; + } + + template < typename E > + vector& events::get() noexcept { + return events_; + } + + template < typename E > + const vector& events::get() const noexcept { + return events_; + } + template < typename E > events& events::clear() noexcept { events_.clear(); diff --git a/headers/enduro2d/high/components/spine_player.hpp b/headers/enduro2d/high/components/spine_player.hpp index a0a449a5..76d32ab1 100644 --- a/headers/enduro2d/high/components/spine_player.hpp +++ b/headers/enduro2d/high/components/spine_player.hpp @@ -16,6 +16,34 @@ struct spSkeleton; struct spSkeletonClipping; struct spAnimationState; +namespace e2d::spine_player_events +{ + class custom_evt; + class end_evt; + class complete_evt; + + using event = std::variant< + custom_evt, + end_evt, + complete_evt>; +} + +namespace e2d::spine_player_commands +{ + class clear_track_cmd; + class set_anim_cmd; + class add_anim_cmd; + class set_empty_anim_cmd; + class add_empty_anim_cmd; + + using command = std::variant< + clear_track_cmd, + set_anim_cmd, + add_anim_cmd, + set_empty_anim_cmd, + add_empty_anim_cmd>; +} + namespace e2d { class bad_spine_player_access final : public exception { @@ -72,24 +100,50 @@ namespace e2d asset_dependencies& dependencies, const collect_context& ctx) const; }; + + template <> + class factory_loader> final : factory_loader<> { + public: + static const char* schema_source; + + bool operator()( + events& component, + const fill_context& ctx) const; + + bool operator()( + asset_dependencies& dependencies, + const collect_context& ctx) const; + }; + + template <> + class factory_loader> final : factory_loader<> { + public: + static const char* schema_source; + + bool operator()( + commands& component, + const fill_context& ctx) const; + + bool operator()( + asset_dependencies& dependencies, + const collect_context& ctx) const; + }; } namespace e2d::spine_player_events { - class custom_evt; - class end_evt; - class complete_evt; - - using event = std::variant< - custom_evt, - end_evt, - complete_evt>; - class custom_evt final { public: + custom_evt() = default; + custom_evt(str name) : name_(std::move(name)) {} + custom_evt& name(str value) noexcept { + name_ = std::move(value); + return *this; + } + custom_evt& int_value(i32 value) noexcept { int_value_ = value; return *this; @@ -118,9 +172,16 @@ namespace e2d::spine_player_events class end_evt final { public: + end_evt() = default; + end_evt(str message) : message_(std::move(message)) {} + end_evt& message(str value) noexcept { + message_ = std::move(value); + return *this; + } + [[nodiscard]] const str& message() const noexcept { return message_; } private: str message_; @@ -128,9 +189,16 @@ namespace e2d::spine_player_events class complete_evt final { public: + complete_evt() = default; + complete_evt(str message) : message_(std::move(message)) {} + complete_evt& message(str value) noexcept { + message_ = std::move(value); + return *this; + } + [[nodiscard]] const str& message() const noexcept { return message_; } private: str message_; @@ -139,19 +207,6 @@ namespace e2d::spine_player_events namespace e2d::spine_player_commands { - class clear_track_cmd; - class set_anim_cmd; - class add_anim_cmd; - class set_empty_anim_cmd; - class add_empty_anim_cmd; - - using command = std::variant< - clear_track_cmd, - set_anim_cmd, - add_anim_cmd, - set_empty_anim_cmd, - add_empty_anim_cmd>; - class clear_track_cmd final { public: clear_track_cmd(u32 track) diff --git a/samples/bin/library/prefabs/coin_prefab.json b/samples/bin/library/prefabs/coin_prefab.json index d8b7452b..09a3ce8d 100644 --- a/samples/bin/library/prefabs/coin_prefab.json +++ b/samples/bin/library/prefabs/coin_prefab.json @@ -3,6 +3,16 @@ "components" : { "spine_player" : { "spine" : "../spines/coin_spine.json" + }, + "spine_player_commands" : { + "commands" : [{ + "type" : "set_anim_cmd", + "desc" : { + "track" : 0, + "name" : "animation", + "loop" : true + } + }] } } } diff --git a/samples/bin/library/prefabs/dragon_prefab.json b/samples/bin/library/prefabs/dragon_prefab.json index 59606364..46d90168 100644 --- a/samples/bin/library/prefabs/dragon_prefab.json +++ b/samples/bin/library/prefabs/dragon_prefab.json @@ -3,6 +3,16 @@ "components" : { "spine_player" : { "spine" : "../spines/dragon_spine.json" + }, + "spine_player_commands" : { + "commands" : [{ + "type" : "set_anim_cmd", + "desc" : { + "track" : 0, + "name" : "flying", + "loop" : true + } + }] } } } diff --git a/samples/bin/library/prefabs/raptor_prefab.json b/samples/bin/library/prefabs/raptor_prefab.json index 215be494..9204152b 100644 --- a/samples/bin/library/prefabs/raptor_prefab.json +++ b/samples/bin/library/prefabs/raptor_prefab.json @@ -3,6 +3,42 @@ "components" : { "spine_player" : { "spine" : "../spines/raptor_spine.json" + }, + "spine_player_commands" : { + "commands" : [{ + "type" : "add_anim_cmd", + "desc" : { + "track" : 0, + "name" : "walk" + } + }, { + "type" : "add_anim_cmd", + "desc" : { + "track" : 0, + "name" : "roar" + } + }, { + "type" : "add_anim_cmd", + "desc" : { + "track" : 0, + "name" : "walk", + "loop" : true + } + }, { + "type" : "add_anim_cmd", + "desc" : { + "track" : 1, + "name" : "gun-grab", + "delay" : 2 + } + }, { + "type" : "add_anim_cmd", + "desc" : { + "track" : 1, + "name" : "gun-holster", + "delay" : 3 + } + }] } } } diff --git a/samples/bin/library/prefabs/spine_prefab.json b/samples/bin/library/prefabs/spine_prefab.json index a132aa36..2d34d33a 100644 --- a/samples/bin/library/prefabs/spine_prefab.json +++ b/samples/bin/library/prefabs/spine_prefab.json @@ -8,6 +8,8 @@ "normal" : "../materials/spine_material_normal.json", "screen" : "../materials/spine_material_screen.json" } - } + }, + "spine_player_events" : {}, + "spine_player_commands" : {} } } diff --git a/samples/bin/library/scripts/emmy/components/spine_player.lua b/samples/bin/library/scripts/emmy/components/spine_player.lua index 404de54f..8bde698f 100644 --- a/samples/bin/library/scripts/emmy/components/spine_player.lua +++ b/samples/bin/library/scripts/emmy/components/spine_player.lua @@ -56,9 +56,10 @@ spine_player.custom_evt = { string_value = "" } ----@param name string +---@overload fun(): spine_player_custom_evt +---@overload fun(name: string): spine_player_custom_evt ---@return spine_player_custom_evt -function spine_player.custom_evt.new(name) end +function spine_player.custom_evt.new(...) end -- -- end_evt @@ -70,12 +71,13 @@ spine_player.end_evt = { message = "" } ----@param message string +---@overload fun(): spine_player_end_evt +---@overload fun(message: string): spine_player_end_evt ---@return spine_player_end_evt -function spine_player.end_evt.new(message) end +function spine_player.end_evt.new(...) end -- --- complete_evt +-- complete -- ---@class spine_player_complete_evt @@ -84,9 +86,10 @@ spine_player.complete_evt = { message = "" } ----@param message string +---@overload fun(): spine_player_complete_evt +---@overload fun(message: string): spine_player_complete_evt ---@return spine_player_complete_evt -function spine_player.complete_evt.new(message) end +function spine_player.complete_evt.new(...) end -- ----------------------------------------------------------------------------- -- diff --git a/samples/sources/sample_06/sample_06.cpp b/samples/sources/sample_06/sample_06.cpp index 7734a5cb..2f676fcd 100644 --- a/samples/sources/sample_06/sample_06.cpp +++ b/samples/sources/sample_06/sample_06.cpp @@ -57,9 +57,9 @@ namespace owner.for_joined_components>([ ](ecs::entity e, const events& pe) { - for ( const auto& evt : pe ) { - if ( auto complete_evt = std::get_if(&evt); - complete_evt && complete_evt->message() == "to_walk" ) + for ( const auto& evt : pe.get() ) { + if ( auto complete = std::get_if(&evt); + complete && complete->message() == "to_walk" ) { e.ensure_component>() .add(spine_player_commands::add_anim_cmd(0, "walk") diff --git a/scripts/cloc_all.sh b/scripts/cloc_all.sh index f6abdbd9..8562034a 100755 --- a/scripts/cloc_all.sh +++ b/scripts/cloc_all.sh @@ -3,5 +3,7 @@ SCRIPT_DIR=`dirname "$BASH_SOURCE"` cloc \ $SCRIPT_DIR/../headers/enduro2d \ $SCRIPT_DIR/../sources/enduro2d \ + $SCRIPT_DIR/../samples/bin \ $SCRIPT_DIR/../samples/sources \ + $SCRIPT_DIR/../untests/bin \ $SCRIPT_DIR/../untests/sources diff --git a/scripts/cloc_samples.sh b/scripts/cloc_samples.sh index 92c40dbc..cfe95c03 100755 --- a/scripts/cloc_samples.sh +++ b/scripts/cloc_samples.sh @@ -1,3 +1,5 @@ #!/bin/bash SCRIPT_DIR=`dirname "$BASH_SOURCE"` -cloc $SCRIPT_DIR/../samples/sources +cloc \ + $SCRIPT_DIR/../samples/bin \ + $SCRIPT_DIR/../samples/sources diff --git a/scripts/cloc_untests.sh b/scripts/cloc_untests.sh index 59cf1a7b..119b7549 100755 --- a/scripts/cloc_untests.sh +++ b/scripts/cloc_untests.sh @@ -1,3 +1,5 @@ #!/bin/bash SCRIPT_DIR=`dirname "$BASH_SOURCE"` -cloc $SCRIPT_DIR/../untests/sources +cloc \ + $SCRIPT_DIR/../untests/bin \ + $SCRIPT_DIR/../untests/sources diff --git a/sources/enduro2d/high/bindings/high_binds/components/spine_player_binds.cpp b/sources/enduro2d/high/bindings/high_binds/components/spine_player_binds.cpp index 1503dd60..fc0f57ee 100644 --- a/sources/enduro2d/high/bindings/high_binds/components/spine_player_binds.cpp +++ b/sources/enduro2d/high/bindings/high_binds/components/spine_player_binds.cpp @@ -58,12 +58,15 @@ namespace e2d::bindings::high l["spine_player"].get_or_create() .new_usertype("custom_evt", sol::constructors< + spine_player_events::custom_evt(), spine_player_events::custom_evt(str)>(), "name", sol::property( [](const spine_player_events::custom_evt& c) -> str { return c.name(); - }), + }, + sol::resolve( + &spine_player_events::custom_evt::name)), "int_value", sol::property( [](const spine_player_events::custom_evt& c) -> i32 { @@ -90,23 +93,29 @@ namespace e2d::bindings::high l["spine_player"].get_or_create() .new_usertype("end_evt", sol::constructors< + spine_player_events::end_evt(), spine_player_events::end_evt(str)>(), "message", sol::property( [](const spine_player_events::end_evt& c) -> str { return c.message(); - }) + }, + sol::resolve( + &spine_player_events::end_evt::message)) ); l["spine_player"].get_or_create() .new_usertype("complete_evt", sol::constructors< + spine_player_events::complete_evt(), spine_player_events::complete_evt(str)>(), "message", sol::property( [](const spine_player_events::complete_evt& c) -> str { return c.message(); - }) + }, + sol::resolve( + &spine_player_events::complete_evt::message)) ); // @@ -115,8 +124,7 @@ namespace e2d::bindings::high l["spine_player"].get_or_create() .new_usertype("clear_track_cmd", - sol::constructors< - spine_player_commands::clear_track_cmd(u32)>(), + sol::constructors(), "track", sol::property( [](const spine_player_commands::clear_track_cmd& c) -> u32 { @@ -126,8 +134,7 @@ namespace e2d::bindings::high l["spine_player"].get_or_create() .new_usertype("set_anim_cmd", - sol::constructors< - spine_player_commands::set_anim_cmd(u32,str)>(), + sol::constructors(), "track", sol::property( [](const spine_player_commands::set_anim_cmd& c) -> u32 { @@ -163,8 +170,7 @@ namespace e2d::bindings::high l["spine_player"].get_or_create() .new_usertype("add_anim_cmd", - sol::constructors< - spine_player_commands::add_anim_cmd(u32,str)>(), + sol::constructors(), "track", sol::property( [](const spine_player_commands::add_anim_cmd& c) -> u32 { @@ -207,8 +213,7 @@ namespace e2d::bindings::high l["spine_player"].get_or_create() .new_usertype("set_empty_anim_cmd", - sol::constructors< - spine_player_commands::set_empty_anim_cmd(u32)>(), + sol::constructors(), "track", sol::property( [](const spine_player_commands::set_empty_anim_cmd& c) -> u32 { diff --git a/sources/enduro2d/high/components/spine_player.cpp b/sources/enduro2d/high/components/spine_player.cpp index 82372206..53b99363 100644 --- a/sources/enduro2d/high/components/spine_player.cpp +++ b/sources/enduro2d/high/components/spine_player.cpp @@ -6,8 +6,407 @@ #include +#include +#include + #include +namespace +{ + using namespace e2d; + + std::optional parse_custom_evt(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + spine_player_events::custom_evt evt; + + if ( root.HasMember("name") ) { + str evt_name = evt.name(); + if ( !json_utils::try_parse_value(root["name"], evt_name) ) { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.name' property"); + return std::nullopt; + } + evt.name(std::move(evt_name)); + } + + if ( root.HasMember("int_value") ) { + i32 evt_int_value = evt.int_value(); + if ( !json_utils::try_parse_value(root["int_value"], evt_int_value) ) { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.int_value' property"); + return std::nullopt; + } + evt.int_value(evt_int_value); + } + + if ( root.HasMember("float_value") ) { + f32 evt_float_value = evt.float_value(); + if ( !json_utils::try_parse_value(root["float_value"], evt_float_value) ) { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.float_value' property"); + return std::nullopt; + } + evt.float_value(evt_float_value); + } + + if ( root.HasMember("string_value") ) { + str evt_string_value = evt.string_value(); + if ( !json_utils::try_parse_value(root["string_value"], evt_string_value) ) { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.string_value' property"); + return std::nullopt; + } + evt.string_value(std::move(evt_string_value)); + } + + return evt; + } + + std::optional parse_end_evt(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + spine_player_events::end_evt evt; + + if ( root.HasMember("message") ) { + str evt_message = evt.message(); + if ( !json_utils::try_parse_value(root["message"], evt_message) ) { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'end_evt.message' property"); + return std::nullopt; + } + evt.message(std::move(evt_message)); + } + + return evt; + } + + std::optional parse_complete_evt(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + spine_player_events::complete_evt evt; + + if ( root.HasMember("message") ) { + str evt_message = evt.message(); + if ( !json_utils::try_parse_value(root["message"], evt_message) ) { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'complete_evt.message' property"); + return std::nullopt; + } + evt.message(std::move(evt_message)); + } + + return evt; + } + + std::optional parse_event(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + str_hash command_type; + E2D_ASSERT(root.HasMember("type") && root["type"].IsString()); + if ( !json_utils::try_parse_value(root["type"], command_type) ) { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'event.type' property"); + return std::nullopt; + } + + E2D_ASSERT(root.HasMember("desc") && root["desc"].IsObject()); + const auto& event_desc = root["desc"]; + + if ( command_type == make_hash("custom_evt") ) { + auto evt = parse_custom_evt(event_desc); + return evt ? evt : std::nullopt; + } else if ( command_type == make_hash("end_evt") ) { + auto evt = parse_end_evt(event_desc); + return evt ? evt : std::nullopt; + } else if ( command_type == make_hash("complete_evt") ) { + auto evt = parse_complete_evt(event_desc); + return evt ? evt : std::nullopt; + } else { + the().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'event.type' property"); + return std::nullopt; + } + } + + std::optional> parse_events(const rapidjson::Value& root) { + E2D_ASSERT(root.IsArray()); + + vector evts; + evts.reserve(root.Size()); + + for ( rapidjson::SizeType i = 0; i < root.Size(); ++i ) { + auto evt = parse_event(root[i]); + if ( !evt ) { + return std::nullopt; + } + evts.push_back(std::move(*evt)); + } + + return evts; + } +} + +namespace +{ + using namespace e2d; + + std::optional parse_clear_track_cmd(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + u32 cmd_track{0u}; + if ( !json_utils::try_parse_value(root["track"], cmd_track) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'clear_track_cmd.track' property"); + return std::nullopt; + } + + return spine_player_commands::clear_track_cmd(cmd_track); + } + + std::optional parse_set_anim_cmd(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + u32 cmd_track{0u}; + E2D_ASSERT(root.HasMember("track")); + if ( !json_utils::try_parse_value(root["track"], cmd_track) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.track' property"); + return std::nullopt; + } + + str cmd_name; + E2D_ASSERT(root.HasMember("name")); + if ( !json_utils::try_parse_value(root["name"], cmd_name) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.name' property"); + return std::nullopt; + } + + spine_player_commands::set_anim_cmd cmd(cmd_track, std::move(cmd_name)); + + if ( root.HasMember("loop") ) { + bool cmd_loop = cmd.loop(); + if ( !json_utils::try_parse_value(root["loop"], cmd_loop) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.loop' property"); + return std::nullopt; + } + cmd.loop(cmd_loop); + } + + if ( root.HasMember("end_message") ) { + str cmd_end_message = cmd.end_message(); + if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.end_message' property"); + return std::nullopt; + } + cmd.end_message(std::move(cmd_end_message)); + } + + if ( root.HasMember("complete_message") ) { + str cmd_complete_message = cmd.complete_message(); + if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.complete_message' property"); + return std::nullopt; + } + cmd.complete_message(std::move(cmd_complete_message)); + } + + return cmd; + } + + std::optional parse_add_anim_cmd(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + u32 cmd_track{0u}; + E2D_ASSERT(root.HasMember("track")); + if ( !json_utils::try_parse_value(root["track"], cmd_track) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.track' property"); + return std::nullopt; + } + + str cmd_name; + E2D_ASSERT(root.HasMember("name")); + if ( !json_utils::try_parse_value(root["name"], cmd_name) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.name' property"); + return std::nullopt; + } + + spine_player_commands::add_anim_cmd cmd(cmd_track, std::move(cmd_name)); + + if ( root.HasMember("loop") ) { + bool cmd_loop = cmd.loop(); + if ( !json_utils::try_parse_value(root["loop"], cmd_loop) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.loop' property"); + return std::nullopt; + } + cmd.loop(cmd_loop); + } + + if ( root.HasMember("delay") ) { + f32 cmd_delay = cmd.delay(); + if ( !json_utils::try_parse_value(root["delay"], cmd_delay) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.delay' property"); + return std::nullopt; + } + cmd.delay(cmd_delay); + } + + if ( root.HasMember("end_message") ) { + str cmd_end_message = cmd.end_message(); + if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.end_message' property"); + return std::nullopt; + } + cmd.end_message(std::move(cmd_end_message)); + } + + if ( root.HasMember("complete_message") ) { + str cmd_complete_message = cmd.complete_message(); + if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.complete_message' property"); + return std::nullopt; + } + cmd.complete_message(std::move(cmd_complete_message)); + } + + return cmd; + } + + std::optional parse_set_empty_anim_cmd(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + u32 cmd_track{0u}; + E2D_ASSERT(root.HasMember("track")); + if ( !json_utils::try_parse_value(root["track"], cmd_track) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.track' property"); + return std::nullopt; + } + + spine_player_commands::set_empty_anim_cmd cmd(cmd_track); + + if ( root.HasMember("mix_duration") ) { + f32 cmd_mix_duration = cmd.mix_duration(); + if ( !json_utils::try_parse_value(root["mix_duration"], cmd_mix_duration) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.mix_duration' property"); + return std::nullopt; + } + cmd.mix_duration(cmd_mix_duration); + } + + if ( root.HasMember("end_message") ) { + str cmd_end_message = cmd.end_message(); + if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.end_message' property"); + return std::nullopt; + } + cmd.end_message(std::move(cmd_end_message)); + } + + if ( root.HasMember("complete_message") ) { + str cmd_complete_message = cmd.complete_message(); + if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.complete_message' property"); + return std::nullopt; + } + cmd.complete_message(std::move(cmd_complete_message)); + } + + return cmd; + } + + std::optional parse_add_empty_anim_cmd(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + u32 cmd_track{0u}; + E2D_ASSERT(root.HasMember("track")); + if ( !json_utils::try_parse_value(root["track"], cmd_track) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.track' property"); + return std::nullopt; + } + + spine_player_commands::add_empty_anim_cmd cmd(cmd_track); + + if ( root.HasMember("delay") ) { + f32 cmd_delay = cmd.delay(); + if ( !json_utils::try_parse_value(root["delay"], cmd_delay) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.delay' property"); + return std::nullopt; + } + cmd.delay(cmd_delay); + } + + if ( root.HasMember("mix_duration") ) { + f32 cmd_mix_duration = cmd.mix_duration(); + if ( !json_utils::try_parse_value(root["mix_duration"], cmd_mix_duration) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.mix_duration' property"); + return std::nullopt; + } + cmd.mix_duration(cmd_mix_duration); + } + + if ( root.HasMember("end_message") ) { + str cmd_end_message = cmd.end_message(); + if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.end_message' property"); + return std::nullopt; + } + cmd.end_message(std::move(cmd_end_message)); + } + + if ( root.HasMember("complete_message") ) { + str cmd_complete_message = cmd.complete_message(); + if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.complete_message' property"); + return std::nullopt; + } + cmd.complete_message(std::move(cmd_complete_message)); + } + + return cmd; + } + + std::optional parse_command(const rapidjson::Value& root) { + E2D_ASSERT(root.IsObject()); + + str_hash command_type; + E2D_ASSERT(root.HasMember("type") && root["type"].IsString()); + if ( !json_utils::try_parse_value(root["type"], command_type) ) { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'command.type' property"); + return std::nullopt; + } + + E2D_ASSERT(root.HasMember("desc") && root["desc"].IsObject()); + const auto& command_desc = root["desc"]; + + if ( command_type == make_hash("clear_track_cmd") ) { + auto cmd = parse_clear_track_cmd(command_desc); + return cmd ? cmd : std::nullopt; + } else if ( command_type == make_hash("set_anim_cmd") ) { + auto cmd = parse_set_anim_cmd(command_desc); + return cmd ? cmd : std::nullopt; + } else if ( command_type == make_hash("add_anim_cmd") ) { + auto cmd = parse_add_anim_cmd(command_desc); + return cmd ? cmd : std::nullopt; + } else if ( command_type == make_hash("set_empty_anim_cmd") ) { + auto cmd = parse_set_empty_anim_cmd(command_desc); + return cmd ? cmd : std::nullopt; + } else if ( command_type == make_hash("add_empty_anim_cmd") ) { + auto cmd = parse_add_empty_anim_cmd(command_desc); + return cmd ? cmd : std::nullopt; + } else { + the().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'command.type' property"); + return std::nullopt; + } + } + + std::optional> parse_commands(const rapidjson::Value& root) { + E2D_ASSERT(root.IsArray()); + + vector cmds; + cmds.reserve(root.Size()); + + for ( rapidjson::SizeType i = 0; i < root.Size(); ++i ) { + auto cmd = parse_command(root[i]); + if ( !cmd ) { + return std::nullopt; + } + cmds.push_back(std::move(*cmd)); + } + + return cmds; + } +} + namespace e2d { spine_player::spine_player(const spine_asset::ptr& spine) { @@ -107,7 +506,7 @@ namespace e2d const spine_asset::ptr& spine_player::spine() const noexcept { return spine_; } - + const spine_player::clipping_ptr& spine_player::clipper() const noexcept { return clipping_; } @@ -291,3 +690,222 @@ namespace e2d return true; } } + +namespace e2d +{ + const char* factory_loader>::schema_source = R"json({ + "type" : "object", + "required" : [], + "additionalProperties" : false, + "properties" : { + "commands" : { "$ref": "#/definitions/events" } + }, + "definitions" : { + "events" : { + "type" : "array", + "items" : { "$ref": "#/definitions/event" } + }, + "event" : { + "type" : "object", + "required" : [ "type", "desc" ], + "additionalProperties" : false, + "properties" : { + "type" : { "$ref": "#/common_definitions/name" }, + "desc" : { + "anyOf" : [{ + "$ref" : "#/definitions/custom_evt" + }, { + "$ref" : "#/definitions/end" + }, { + "$ref" : "#/definitions/complete" + }] + } + } + }, + "custom_evt" : { + "type" : "object", + "required" : [], + "additionalProperties" : false, + "properties" : { + "name" : { "type" : "string" }, + "int_value" : { "type" : "integer" }, + "float_value" : { "type" : "number" }, + "string_value" : { "type" : "string" } + } + }, + "end" : { + "type" : "object", + "required" : [], + "additionalProperties" : false, + "properties" : { + "message" : { "type" : "string" } + } + }, + "complete" : { + "type" : "object", + "required" : [], + "additionalProperties" : false, + "properties" : { + "message" : { "type" : "string" } + } + } + } + })json"; + + bool factory_loader>::operator()( + events& component, + const fill_context& ctx) const + { + if ( ctx.root.HasMember("events") ) { + auto evts = parse_events(ctx.root["events"]); + + if ( !evts ) { + return false; + } + + for ( auto& evt : *evts ) { + if ( evt.valueless_by_exception() ) { + return false; + } + } + + component.set(std::move(*evts)); + } + + return true; + } + + bool factory_loader>::operator()( + asset_dependencies& dependencies, + const collect_context& ctx) const + { + E2D_UNUSED(dependencies, ctx); + return true; + } +} + +namespace e2d +{ + const char* factory_loader>::schema_source = R"json({ + "type" : "object", + "required" : [], + "additionalProperties" : false, + "properties" : { + "commands" : { "$ref": "#/definitions/commands" } + }, + "definitions" : { + "commands" : { + "type" : "array", + "items" : { "$ref": "#/definitions/command" } + }, + "command" : { + "type" : "object", + "required" : [ "type", "desc" ], + "additionalProperties" : false, + "properties" : { + "type" : { "$ref": "#/common_definitions/name" }, + "desc" : { + "anyOf" : [{ + "$ref" : "#/definitions/clear_track_cmd" + }, { + "$ref" : "#/definitions/set_anim_cmd" + }, { + "$ref" : "#/definitions/add_anim_cmd" + }, { + "$ref" : "#/definitions/set_empty_anim_cmd" + }, { + "$ref" : "#/definitions/add_empty_anim_cmd" + }] + } + } + }, + "clear_track_cmd" : { + "type" : "object", + "required" : [ "track" ], + "additionalProperties" : false, + "properties" : { + "track" : { "type" : "integer", "minimum" : 0 } + } + }, + "set_anim_cmd" : { + "type" : "object", + "required" : [ "track", "name" ], + "additionalProperties" : false, + "properties" : { + "track" : { "type" : "integer", "minimum" : 0 }, + "name" : { "$ref": "#/common_definitions/name" }, + "loop" : { "type" : "boolean" }, + "end_message" : { "type" : "string" }, + "complete_message" : { "type" : "string" } + } + }, + "add_anim_cmd" : { + "type" : "object", + "required" : [ "track", "name" ], + "additionalProperties" : false, + "properties" : { + "track" : { "type" : "integer", "minimum" : 0 }, + "name" : { "$ref": "#/common_definitions/name" }, + "loop" : { "type" : "boolean" }, + "delay" : { "type" : "number" }, + "end_message" : { "type" : "string" }, + "complete_message" : { "type" : "string" } + } + }, + "set_empty_anim_cmd" : { + "type" : "object", + "required" : [ "track" ], + "additionalProperties" : false, + "properties" : { + "track" : { "type" : "integer", "minimum" : 0 }, + "mix_duration" : { "type" : "number" }, + "end_message" : { "type" : "string" }, + "complete_message" : { "type" : "string" } + } + }, + "add_empty_anim_cmd" : { + "type" : "object", + "required" : [ "track" ], + "additionalProperties" : false, + "properties" : { + "track" : { "type" : "integer", "minimum" : 0 }, + "delay" : { "type" : "number" }, + "mix_duration" : { "type" : "number" }, + "end_message" : { "type" : "string" }, + "complete_message" : { "type" : "string" } + } + } + } + })json"; + + bool factory_loader>::operator()( + commands& component, + const fill_context& ctx) const + { + if ( ctx.root.HasMember("commands") ) { + auto cmds = parse_commands(ctx.root["commands"]); + + if ( !cmds ) { + return false; + } + + for ( auto& cmd : *cmds ) { + if ( cmd.valueless_by_exception() ) { + return false; + } + } + + component.set(std::move(*cmds)); + } + + return true; + } + + bool factory_loader>::operator()( + asset_dependencies& dependencies, + const collect_context& ctx) const + { + E2D_UNUSED(dependencies, ctx); + return true; + } +} diff --git a/sources/enduro2d/high/starter.cpp b/sources/enduro2d/high/starter.cpp index 07c0ab79..41a8d2cf 100644 --- a/sources/enduro2d/high/starter.cpp +++ b/sources/enduro2d/high/starter.cpp @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -186,6 +189,8 @@ namespace e2d .register_component("renderer") .register_component("scene") .register_component("spine_player") + .register_component>("spine_player_events") + .register_component>("spine_player_commands") .register_component("sprite_renderer"); safe_module_initialize(); diff --git a/sources/enduro2d/high/systems/script_system.cpp b/sources/enduro2d/high/systems/script_system.cpp index 773df97a..142f48dd 100644 --- a/sources/enduro2d/high/systems/script_system.cpp +++ b/sources/enduro2d/high/systems/script_system.cpp @@ -51,7 +51,7 @@ namespace if ( !a.node() || !a.node()->owner() ) { return; } - for ( const spine_player_events::event& evt : es ) { + for ( const spine_player_events::event& evt : es.get() ) { behaviours::call_result r = behaviours::call_result::success; std::visit(utils::overloaded { [&b,&a,&r](const spine_player_events::custom_evt& e){ diff --git a/sources/enduro2d/high/systems/spine_system.cpp b/sources/enduro2d/high/systems/spine_system.cpp index ede301f7..4ec2d47f 100644 --- a/sources/enduro2d/high/systems/spine_system.cpp +++ b/sources/enduro2d/high/systems/spine_system.cpp @@ -210,7 +210,7 @@ namespace } command_visitor v(e, *skeleton->data, *animation_state); - for ( const auto& cmd : cs ) { + for ( const auto& cmd : cs.get() ) { std::visit(v, cmd); } });