diff --git a/ecsact/entt/detail/internal_markers.hh b/ecsact/entt/detail/internal_markers.hh index c80129c..5c8eb8f 100644 --- a/ecsact/entt/detail/internal_markers.hh +++ b/ecsact/entt/detail/internal_markers.hh @@ -72,6 +72,9 @@ struct system_sorted { template struct pending_lazy_execution {}; +template +struct run_system {}; + template constexpr bool system_markers_unimplemented_by_codegen = false; diff --git a/ecsact/entt/event_markers.hh b/ecsact/entt/event_markers.hh index 11c1c4d..2fa0e58 100644 --- a/ecsact/entt/event_markers.hh +++ b/ecsact/entt/event_markers.hh @@ -14,7 +14,7 @@ struct component_added {}; * Marker to indicate that a component has been changed during execution */ template -struct component_changed {}; +struct component_updated {}; /** * Marker to indicate that a component has been removed diff --git a/ecsact/entt/wrapper/core.hh b/ecsact/entt/wrapper/core.hh index 0ece0cb..7d10d1a 100644 --- a/ecsact/entt/wrapper/core.hh +++ b/ecsact/entt/wrapper/core.hh @@ -153,7 +153,7 @@ inline auto update_component_exec_options( // if(err == ECSACT_UPDATE_OK) { reg.replace(entity, *static_cast(component_data)); - reg.template emplace_or_replace>(entity); + reg.template emplace_or_replace>(entity); } return err; @@ -174,7 +174,7 @@ auto remove_component( reg.remove>(entity); } reg.template remove>(entity); - reg.template remove>(entity); + reg.template remove>(entity); reg.template emplace_or_replace>(entity); ecsact::entt::detail::remove_system_markers_if_needed(reg, entity); } @@ -200,7 +200,7 @@ auto remove_component_exec_options( reg.template erase(entity); reg.template remove>(entity); - reg.template remove>(entity); + reg.template remove>(entity); reg.template emplace_or_replace>(entity); if constexpr(!std::is_empty_v) { @@ -292,7 +292,7 @@ auto _trigger_update_component_event( ecsact_registry_id registry_id, ecsact::entt::detail::execution_events_collector& events_collector ) -> void { - using ecsact::entt::component_changed; + using ecsact::entt::component_updated; using ecsact::entt::detail::beforechange_storage; if(!events_collector.has_update_callback()) { @@ -304,7 +304,7 @@ auto _trigger_update_component_event( ::entt::basic_view changed_view{ reg.template storage(), reg.template storage>(), - reg.template storage>(), + reg.template storage>(), }; for(ecsact::entt::entity_id entity : changed_view) { @@ -379,10 +379,17 @@ inline auto clear_component(ecsact_registry_id registry_id) -> void { auto& reg = ecsact::entt::get_registry(registry_id); reg.clear>(); - reg.clear>(); + reg.clear>(); reg.clear>(); } +template +inline auto clear_notify_component(ecsact_registry_id registry_id) -> void { + auto& reg = ecsact::entt::get_registry(registry_id); + + reg.clear>(); +} + template inline auto prepare_component(ecsact_registry_id registry_id) -> void { using namespace ecsact::entt; @@ -395,7 +402,7 @@ inline auto prepare_component(ecsact_registry_id registry_id) -> void { if constexpr(!std::is_empty_v) { reg.storage>(); - reg.template storage>(); + reg.template storage>(); } } diff --git a/ecsact/entt/wrapper/dynamic.hh b/ecsact/entt/wrapper/dynamic.hh index f66e28b..afcc37f 100644 --- a/ecsact/entt/wrapper/dynamic.hh +++ b/ecsact/entt/wrapper/dynamic.hh @@ -81,8 +81,8 @@ auto context_remove( ) -> void { assert(ecsact_id_cast(C::id) == component_id); - using ecsact::entt::component_changed; using ecsact::entt::component_removed; + using ecsact::entt::component_updated; using ecsact::entt::detail::beforeremove_storage; using ecsact::entt::detail::pending_remove; @@ -90,7 +90,7 @@ auto context_remove( auto& registry = *context->registry; registry.template remove>(entity); - registry.template remove>(entity); + registry.template remove>(entity); registry.template emplace_or_replace>(entity); registry.template emplace_or_replace>(entity); @@ -110,13 +110,13 @@ auto component_remove_trivial( ::entt::registry& registry, ecsact::entt::entity_id entity_id ) -> void { - using ecsact::entt::component_changed; using ecsact::entt::component_removed; + using ecsact::entt::component_updated; using ecsact::entt::detail::beforeremove_storage; using ecsact::entt::detail::pending_remove; registry.template remove>(entity_id); - registry.template remove>(entity_id); + registry.template remove>(entity_id); registry.template emplace_or_replace>(entity_id); registry.template emplace_or_replace>(entity_id); @@ -150,7 +150,7 @@ auto context_update( [[maybe_unused]] ecsact_component_like_id component_id, const void* in_component_data ) -> void { - using ecsact::entt::component_changed; + using ecsact::entt::component_updated; // TODO(Kelwan): for remove, beforeremove_storage auto entity = context->entity; @@ -160,7 +160,7 @@ auto context_update( auto& current_component = registry.template get(entity); current_component = in_component; - registry.template emplace_or_replace>(entity); + registry.template emplace_or_replace>(entity); } template diff --git a/rt_entt_codegen/core/BUILD.bazel b/rt_entt_codegen/core/BUILD.bazel index d126466..40eea6d 100644 --- a/rt_entt_codegen/core/BUILD.bazel +++ b/rt_entt_codegen/core/BUILD.bazel @@ -21,6 +21,7 @@ _CORE_CODEGEN_METHODS = { "print_sys_exec": [ "//rt_entt_codegen/shared:comps_with_caps", "//rt_entt_codegen/shared:sorting", + "//rt_entt_codegen/shared:system_util", "@entt//:entt", "@ecsact_rt_entt//:lib", ], @@ -32,6 +33,7 @@ _CORE_CODEGEN_METHODS = { "system_markers": [ "//rt_entt_codegen/shared:sorting", ], + "system_notify": ["//rt_entt_codegen/shared:system_util"], } [cc_library( diff --git a/rt_entt_codegen/core/core.hh b/rt_entt_codegen/core/core.hh index 41b4d84..073a5b6 100644 --- a/rt_entt_codegen/core/core.hh +++ b/rt_entt_codegen/core/core.hh @@ -66,6 +66,11 @@ auto print_system_marker_remove_fn( const ecsact_entt_details& details ) -> void; +auto print_cleanup_system_notifies( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void; + auto print_entity_match_fn( codegen_plugin_context& ctx, const ecsact_entt_details& details diff --git a/rt_entt_codegen/core/execute_systems.cc b/rt_entt_codegen/core/execute_systems.cc index fd12404..ecc9e22 100644 --- a/rt_entt_codegen/core/execute_systems.cc +++ b/rt_entt_codegen/core/execute_systems.cc @@ -89,6 +89,7 @@ auto ecsact::rt_entt_codegen::core::print_execute_systems( // ); }); ctx.write("cleanup_component_events(registry_id);\n"); + ctx.write("cleanup_system_notifies(registry_id);\n"); }); ctx.write("return ECSACT_EXEC_SYS_OK;"); diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index dd2f7d7..81dafea 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -15,6 +15,7 @@ #include "rt_entt_codegen/shared/util.hh" #include "rt_entt_codegen/shared/comps_with_caps.hh" #include "rt_entt_codegen/shared/sorting.hh" +#include "rt_entt_codegen/shared/system_util.hh" using capability_t = std::unordered_map; @@ -560,6 +561,10 @@ static auto print_ecsact_entt_system_details( using ecsact::meta::decl_full_name; using ecsact::meta::get_child_system_ids; using ecsact::rt_entt_codegen::ecsact_entt_system_details; + using ecsact::rt_entt_codegen::system_util::create_context_struct_name; + using ecsact::rt_entt_codegen::system_util::create_context_var_name; + using ecsact::rt_entt_codegen::system_util::is_notify_system; + using ecsact::rt_entt_codegen::system_util::print_system_notify_views; using ecsact::rt_entt_codegen::util::method_printer; constexpr auto is_system_id = @@ -603,6 +608,18 @@ static auto print_ecsact_entt_system_details( additional_view_components.push_back(system_sorting_struct_name); } + if(is_notify_system(options.sys_like_id)) { + additional_view_components.push_back( + std::format("ecsact::entt::detail::run_system<{}>", options.system_name) + ); + print_system_notify_views( + ctx, + details, + options.sys_like_id, + options.registry_var_name + ); + } + ecsact::rt_entt_codegen::util::make_view( ctx, "view", @@ -771,7 +788,8 @@ static auto print_ecsact_entt_system_details( if(lazy_iteration_rate > 0) { ctx.write( - "// If this assertion triggers that's a ecsact_rt_entt codegen failure\n" + "// If this assertion triggers that's a ecsact_rt_entt codegen " + "failure\n" ); ctx.write("assert(iteration_count_ <= lazy_iteration_rate_);\n"); block(ctx, "if(iteration_count_ < lazy_iteration_rate_)", [&] { @@ -828,31 +846,6 @@ static auto print_ecsact_entt_system_details( ); } -static auto get_unique_view_name() -> std::string { - static int counter = 0; - return "view" + std::to_string(counter++); -} - -template -static auto create_context_struct_name( // - ComponentLikeID component_like_id -) -> std::string { - using ecsact::cc_lang_support::c_identifier; - auto full_name = - c_identifier(ecsact::meta::decl_full_name(component_like_id)); - return full_name + "Struct"; -} - -template -static auto create_context_var_name( // - ComponentLikeID component_like_id -) -> std::string { - using ecsact::cc_lang_support::c_identifier; - auto full_name = - c_identifier(ecsact::meta::decl_full_name(component_like_id)); - return full_name + "_context"; -} - template static auto print_other_contexts( ecsact::codegen_plugin_context& ctx, @@ -866,6 +859,9 @@ static auto print_other_contexts( using ecsact::meta::get_child_system_ids; using ecsact::rt_entt_codegen::ecsact_entt_system_details; using ecsact::rt_entt_codegen::other_key; + using ecsact::rt_entt_codegen::system_util::create_context_struct_name; + using ecsact::rt_entt_codegen::system_util::create_context_var_name; + using ecsact::rt_entt_codegen::system_util::get_unique_view_name; using ecsact::rt_entt_codegen::util::method_printer; std::map other_views; @@ -928,44 +924,6 @@ static auto print_other_contexts( return other_views; } -static auto is_trivial_system(ecsact_system_like_id system_id) -> bool { - using ecsact::meta::get_field_ids; - using ecsact::meta::system_capabilities; - - auto sys_capabilities = system_capabilities(system_id); - - auto non_trivial_capabilities = std::array{ - ECSACT_SYS_CAP_READONLY, - ECSACT_SYS_CAP_READWRITE, - ECSACT_SYS_CAP_WRITEONLY, - ECSACT_SYS_CAP_OPTIONAL_READONLY, - ECSACT_SYS_CAP_OPTIONAL_READWRITE, - ECSACT_SYS_CAP_OPTIONAL_WRITEONLY, - }; - - bool has_non_tag_adds = false; - bool has_read_write = false; - for(auto&& [comp_id, sys_cap] : sys_capabilities) { - if((ECSACT_SYS_CAP_ADDS & sys_cap) == ECSACT_SYS_CAP_ADDS) { - auto field_count = - ecsact_meta_count_fields(ecsact_id_cast(comp_id)); - if(field_count > 0) { - has_non_tag_adds = true; - } - } - - for(auto non_trivial_cap : non_trivial_capabilities) { - if((non_trivial_cap & sys_cap) == sys_cap) { - has_read_write = true; - } - } - } - if(has_non_tag_adds || has_read_write) { - return false; - } - return true; -} - static auto print_trivial_system_like( ecsact::codegen_plugin_context& ctx, const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, @@ -1027,6 +985,7 @@ static auto print_execute_system_template_specialization( using ecsact::cc_lang_support::cpp_identifier; using ecsact::cpp_codegen_plugin_util::block; using ecsact::meta::decl_full_name; + using ecsact::rt_entt_codegen::system_util::is_trivial_system; using ecsact::rt_entt_codegen::util::method_printer; @@ -1076,6 +1035,7 @@ static auto print_execute_actions_template_specialization( using ecsact::cc_lang_support::cpp_identifier; using ecsact::cpp_codegen_plugin_util::block; using ecsact::meta::decl_full_name; + using ecsact::rt_entt_codegen::system_util::is_trivial_system; using ecsact::rt_entt_codegen::util::method_printer; if(is_trivial_system(ecsact_id_cast(action_id))) { diff --git a/rt_entt_codegen/core/system_markers.cc b/rt_entt_codegen/core/system_markers.cc index 1b851f2..9376cbd 100644 --- a/rt_entt_codegen/core/system_markers.cc +++ b/rt_entt_codegen/core/system_markers.cc @@ -75,7 +75,6 @@ auto ecsact::rt_entt_codegen::core::print_system_marker_remove_fn( const ecsact_entt_details& details ) -> void { for(auto comp : details.all_components) { - auto comp_like_id = ecsact_id_cast(comp); auto comp_name = ecsact::meta::decl_full_name(comp); auto comp_cpp_ident = cc_lang_support::cpp_identifier(comp_name); auto sorting_structs_covered = std::set{}; diff --git a/rt_entt_codegen/core/system_notify.cc b/rt_entt_codegen/core/system_notify.cc new file mode 100644 index 0000000..d536f6e --- /dev/null +++ b/rt_entt_codegen/core/system_notify.cc @@ -0,0 +1,38 @@ +#include "rt_entt_codegen/core/core.hh" +#include "ecsact/lang-support/lang-cc.hh" +#include "ecsact/cpp_codegen_plugin_util.hh" +#include "rt_entt_codegen/shared/system_util.hh" + +auto ecsact::rt_entt_codegen::core::print_cleanup_system_notifies( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void { + using ecsact::cc_lang_support::cpp_identifier; + using ecsact::cpp_codegen_plugin_util::block; + using ecsact::meta::decl_full_name; + using ecsact::rt_entt_codegen::util::method_printer; + + auto printer = // + method_printer{ctx, "cleanup_system_notifies"} + .parameter("ecsact_registry_id", "registry_id") + .return_type("void"); + + for(auto system_id : details.all_systems) { + if(!system_util::is_notify_system(system_id)) { + continue; + } + + auto system_name = cpp_identifier(decl_full_name(system_id)); + + ctx.write( + "ecsact::entt::wrapper::core::clear_notify_component<", + system_name, + ">(registry_id);\n" + ); + } +} + +namespace ecsact::rt_entt_codegen::core::notify { +auto print_system_oninit() -> void { +} +} // namespace ecsact::rt_entt_codegen::core::notify diff --git a/rt_entt_codegen/rt_entt_codegen.cc b/rt_entt_codegen/rt_entt_codegen.cc index e983fc4..2e1b8e7 100644 --- a/rt_entt_codegen/rt_entt_codegen.cc +++ b/rt_entt_codegen/rt_entt_codegen.cc @@ -216,6 +216,7 @@ void ecsact_codegen_plugin( core::print_trigger_ecsact_events_all(ctx, details); core::print_cleanup_ecsact_component_events(ctx, details); core::print_execution_options(ctx, details); + core::print_cleanup_system_notifies(ctx, details); core::print_execute_systems(ctx, details); } } diff --git a/rt_entt_codegen/shared/BUILD.bazel b/rt_entt_codegen/shared/BUILD.bazel index 1518ea6..808ec75 100644 --- a/rt_entt_codegen/shared/BUILD.bazel +++ b/rt_entt_codegen/shared/BUILD.bazel @@ -52,3 +52,18 @@ cc_library( "@ecsact_runtime//:meta", ], ) + +cc_library( + name = "system_util", + srcs = ["system_util.cc"], + hdrs = ["system_util.hh"], + copts = copts, + deps = [ + ":ecsact_entt_details", + ":util", + "@ecsact_codegen//:plugin", + "@ecsact_lang_cpp//:cpp_codegen_plugin_util", + "@ecsact_lang_cpp//:support", + "@ecsact_runtime//:meta", + ], +) diff --git a/rt_entt_codegen/shared/system_util.cc b/rt_entt_codegen/shared/system_util.cc new file mode 100644 index 0000000..d86303c --- /dev/null +++ b/rt_entt_codegen/shared/system_util.cc @@ -0,0 +1,173 @@ +#include "system_util.hh" + +#include +#include +#include "rt_entt_codegen/shared/util.hh" + +auto ecsact::rt_entt_codegen::system_util::detail::is_notify_system( + ecsact_system_like_id system_id +) -> bool { + auto count = ecsact::meta::system_notify_settings_count(system_id); + + if(count == 0) { + return false; + } + + auto notify_settings = ecsact::meta::system_notify_settings(system_id); + + for(const auto [comp_id, notify_setting] : notify_settings) { + if(notify_setting == ECSACT_SYS_NOTIFY_ALWAYS || + notify_setting == ECSACT_SYS_NOTIFY_NONE) { + return false; + } + } + + return true; +} + +auto ecsact::rt_entt_codegen::system_util::detail::print_system_notify_views( + ecsact::codegen_plugin_context& ctx, + const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, + ecsact_system_like_id system_id, + std::string registry_name +) -> void { + using ecsact::cc_lang_support::c_identifier; + using ecsact::cc_lang_support::cpp_identifier; + using ecsact::cpp_codegen_plugin_util::block; + using ecsact::meta::component_name; + using ecsact::meta::decl_full_name; + + auto notify_settings = ecsact::meta::system_notify_settings(system_id); + + auto system_name = cpp_identifier(decl_full_name(system_id)); + + for(auto const [comp_id, notify_setting] : notify_settings) { + if(notify_setting == ECSACT_SYS_NOTIFY_ALWAYS || + notify_setting == ECSACT_SYS_NOTIFY_NONE) { + break; + } + auto cpp_comp_name = cpp_identifier(decl_full_name(comp_id)); + auto comp_name = + c_identifier(component_name(static_cast(comp_id))); + + auto run_system_comp = + std::format("ecsact::entt::detail::run_system<{}>", system_name); + + if(notify_setting == ECSACT_SYS_NOTIFY_ONINIT) { + auto pending_add_str = + std::format("ecsact::entt::component_added<{}>", cpp_comp_name); + + auto view_name = std::format("{}_init_view", comp_name); + + ecsact::rt_entt_codegen::util::make_view( + ctx, + view_name, + registry_name, + details, + std::vector{pending_add_str}, + std::vector{run_system_comp} + ); + + block(ctx, std::format("for(auto entity: {})", view_name), [&]() { + ctx.write( + std::format("registry.emplace<{}>(entity);\n", run_system_comp) + ); + }); + } + + if(notify_setting == ECSACT_SYS_NOTIFY_ONREMOVE) { + auto pending_remove_str = + std::format("ecsact::entt::component_removed<{}>", cpp_comp_name); + + auto view_name = std::format("{}_remove_view", comp_name); + + ecsact::rt_entt_codegen::util::make_view( + ctx, + view_name, + registry_name, + details, + std::vector{pending_remove_str}, + std::vector{run_system_comp} + ); + + block(ctx, std::format("for(auto entity: {})", view_name), [&]() { + ctx.write( + std::format("registry.emplace<{}>(entity);\n", run_system_comp) + ); + }); + } + + if(notify_setting == ECSACT_SYS_NOTIFY_ONUPDATE) { + auto component_updated_str = + std::format("ecsact::entt::component_updated<{}>", cpp_comp_name); + + auto view_name = std::format("{}_update_view", comp_name); + + ecsact::rt_entt_codegen::util::make_view( + ctx, + view_name, + registry_name, + details, + std::vector{component_updated_str}, + std::vector{run_system_comp} + ); + + block(ctx, std::format("for(auto entity: {})", view_name), [&]() { + ctx.write( + std::format("registry.emplace<{}>(entity);\n", run_system_comp) + ); + }); + } + + if(notify_setting == ECSACT_SYS_NOTIFY_ONCHANGE) { + // TODO: Implement a component to be checked and added in another PR + // Added when component fields have changed during execution + } + } +} + +auto ecsact::rt_entt_codegen::system_util::is_trivial_system( + ecsact_system_like_id system_id +) -> bool { + using ecsact::meta::get_field_ids; + using ecsact::meta::system_capabilities; + + auto sys_capabilities = system_capabilities(system_id); + + auto non_trivial_capabilities = std::array{ + ECSACT_SYS_CAP_READONLY, + ECSACT_SYS_CAP_READWRITE, + ECSACT_SYS_CAP_WRITEONLY, + ECSACT_SYS_CAP_OPTIONAL_READONLY, + ECSACT_SYS_CAP_OPTIONAL_READWRITE, + ECSACT_SYS_CAP_OPTIONAL_WRITEONLY, + }; + + bool has_non_tag_adds = false; + bool has_read_write = false; + for(auto&& [comp_id, sys_cap] : sys_capabilities) { + if((ECSACT_SYS_CAP_ADDS & sys_cap) == ECSACT_SYS_CAP_ADDS) { + auto field_count = + ecsact_meta_count_fields(ecsact_id_cast(comp_id)); + if(field_count > 0) { + has_non_tag_adds = true; + } + } + + for(auto non_trivial_cap : non_trivial_capabilities) { + if((non_trivial_cap & sys_cap) == sys_cap) { + has_read_write = true; + } + } + } + if(has_non_tag_adds || has_read_write) { + return false; + } + return true; +} + +auto ecsact::rt_entt_codegen::system_util::get_unique_view_name() + -> std::string { + static int counter = 0; + return "view" + std::to_string(counter++); +} diff --git a/rt_entt_codegen/shared/system_util.hh b/rt_entt_codegen/shared/system_util.hh new file mode 100644 index 0000000..488b70d --- /dev/null +++ b/rt_entt_codegen/shared/system_util.hh @@ -0,0 +1,75 @@ +#pragma once + +#include "ecsact/runtime/meta.hh" +#include "ecsact/cpp_codegen_plugin_util.hh" +#include "ecsact/lang-support/lang-cc.hh" +#include "rt_entt_codegen/shared/util.hh" +#include "rt_entt_codegen/shared/ecsact_entt_details.hh" + +namespace ecsact::rt_entt_codegen::system_util { + +namespace detail { +/* + * Checks if a system uses notify and should implement the run_system + * component in its execution + */ +auto is_notify_system(ecsact_system_like_id system_id) -> bool; + +/* + * Prints the specialized views for ecsact_system_notify_settings components + */ +auto print_system_notify_views( + ecsact::codegen_plugin_context& ctx, + const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, + ecsact_system_like_id system_id, + std::string registry_name +) -> void; +} // namespace detail + +template +auto is_notify_system(SystemLikeID system_id) -> bool { + return detail::is_notify_system( + ecsact_id_cast(system_id) + ); +} + +template +auto print_system_notify_views( + ecsact::codegen_plugin_context& ctx, + const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, + SystemLikeID system_id, + std::string registry_name +) -> void { + detail::print_system_notify_views( + ctx, + details, + ecsact_id_cast(system_id), + registry_name + ); +} + +auto is_trivial_system(ecsact_system_like_id system_id) -> bool; + +auto get_unique_view_name() -> std::string; + +template +static auto create_context_struct_name( // + ComponentLikeID component_like_id +) -> std::string { + using ecsact::cc_lang_support::c_identifier; + auto full_name = + c_identifier(ecsact::meta::decl_full_name(component_like_id)); + return full_name + "Struct"; +} + +template +static auto create_context_var_name( // + ComponentLikeID component_like_id +) -> std::string { + using ecsact::cc_lang_support::c_identifier; + auto full_name = + c_identifier(ecsact::meta::decl_full_name(component_like_id)); + return full_name + "_context"; +} + +} // namespace ecsact::rt_entt_codegen::system_util diff --git a/rt_entt_codegen/shared/util.hh b/rt_entt_codegen/shared/util.hh index 5b2deec..e0fbcf5 100644 --- a/rt_entt_codegen/shared/util.hh +++ b/rt_entt_codegen/shared/util.hh @@ -275,7 +275,8 @@ auto make_view( // auto&& view_var_name, auto&& registry_var_name, const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, - std::vector additional_components = {} + std::vector additional_components = {}, + std::vector additional_exclude_components = {} ) -> void { using namespace std::string_literals; using ecsact::rt_entt_codegen::util::comma_delim; @@ -295,13 +296,19 @@ auto make_view( // ctx.write(">("); - if(!details.exclude_comps.empty()) { + auto exclude_comps = details.exclude_comps | + transform(decl_cpp_ident); + + additional_exclude_components.insert( + additional_exclude_components.end(), + exclude_comps.begin(), + exclude_comps.end() + ); + + if(!additional_exclude_components.empty()) { ctx.write( "::entt::exclude<", - comma_delim( - details.exclude_comps | - transform(decl_cpp_ident) - ), + comma_delim(additional_exclude_components), ">" ); } diff --git a/test/runtime_test.cc b/test/runtime_test.cc index 2dc1533..9bf1f50 100644 --- a/test/runtime_test.cc +++ b/test/runtime_test.cc @@ -169,6 +169,36 @@ void runtime_test::ParentSystem::impl(context& ctx) { void runtime_test::ParentSystem::NestedSystem::impl(context& ctx) { } +void runtime_test::InitNotify::impl(context& ctx) { + auto comp = ctx.get(); + comp.val += 1; + ctx.update(comp); +} + +void runtime_test::InitNotifySelective::impl(context& ctx) { + auto comp = ctx.get(); + comp.val += 1; + ctx.update(comp); +} + +void runtime_test::TriggerUpdateNotify::impl(context& ctx) { + auto comp = ctx.get(); + comp.val += 1; + ctx.update(comp); + + ctx.remove(); +} + +void runtime_test::UpdateNotify::impl(context& ctx) { + ctx.add(); +} + +void runtime_test::RemoveNotify::impl(context& ctx) { + auto comp = ctx.get(); + comp.val += 1; + ctx.update(comp); +} + TEST(Core, CreateRegistry) { auto reg_id = ecsact_create_registry("CreateRegistry"); EXPECT_NE(reg_id, ecsact_invalid_registry_id); @@ -1142,3 +1172,194 @@ TEST(Core, StaticSystemImpl) { EXPECT_EQ(comp_get->a, comp.a); } #endif // ECSACT_ENTT_TEST_STATIC_SYSTEM_IMPL + +TEST(Core, NotifyOnInit) { + using runtime_test::NotifyComponentA; + using runtime_test::NotifyComponentB; + using runtime_test::NotifyComponentC; + + auto reg = ecsact::core::registry("NotifyOnInit"); + + auto entity = reg.create_entity(); + + auto notify_comp_a = NotifyComponentA{.val = 0}; + auto notify_comp_b = NotifyComponentB{.val = 0}; + auto notify_comp_c = NotifyComponentC{.val = 0}; + + auto exec_options = ecsact::core::execution_options{}; + auto evc = ecsact::core::execution_events_collector<>{}; + + exec_options.add_component(entity, ¬ify_comp_a); + exec_options.add_component(entity, ¬ify_comp_b); + exec_options.add_component(entity, ¬ify_comp_c); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::InitNotify::id), + runtime_test__InitNotify + ); + + evc.set_update_callback( + [&](ecsact_entity_id, const NotifyComponentA& component) { + ASSERT_EQ(component.val, 1); + } + ); + + auto error = reg.execute_systems(std::array{exec_options}, evc); + ASSERT_EQ(error, ECSACT_EXEC_SYS_OK); + reg.execute_systems(5); + auto updated_comp_a = reg.get_component(entity); + + ASSERT_EQ(updated_comp_a.val, 1); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::InitNotify::id), + nullptr + ); +} + +TEST(Core, NotifyOnInitSelective) { + using runtime_test::NotifyComponentA; + using runtime_test::NotifyComponentB; + using runtime_test::NotifyComponentC; + + auto reg = ecsact::core::registry("NotifyOnInitSelective"); + + auto entity = reg.create_entity(); + + auto notify_comp_a = NotifyComponentA{.val = 0}; + auto notify_comp_b = NotifyComponentB{.val = 0}; + auto notify_comp_c = NotifyComponentC{.val = 0}; + + auto exec_options = ecsact::core::execution_options{}; + auto evc = ecsact::core::execution_events_collector<>{}; + + exec_options.add_component(entity, ¬ify_comp_a); + exec_options.add_component(entity, ¬ify_comp_b); + exec_options.add_component(entity, ¬ify_comp_c); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::InitNotifySelective::id + ), + runtime_test__InitNotifySelective + ); + + auto error = reg.execute_systems(std::array{exec_options}, evc); + ASSERT_EQ(error, ECSACT_EXEC_SYS_OK); + reg.execute_systems(5); + auto updated_comp_a = reg.get_component(entity); + + ASSERT_EQ(updated_comp_a.val, 1); + + exec_options.clear(); + exec_options.remove_component(entity, notify_comp_b.id); + error = reg.execute_systems(std::array{exec_options}, evc); + ASSERT_EQ(error, ECSACT_EXEC_SYS_OK); + + exec_options.clear(); + exec_options.add_component(entity, ¬ify_comp_b); + error = reg.execute_systems(std::array{exec_options}, evc); + ASSERT_EQ(error, ECSACT_EXEC_SYS_OK); + reg.execute_systems(5); + + updated_comp_a = reg.get_component(entity); + ASSERT_EQ(updated_comp_a.val, 2); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::InitNotifySelective::id + ), + nullptr + ); +} + +TEST(Core, NotifyOnRemove) { + using runtime_test::NotifyComponentA; + using runtime_test::NotifyComponentB; + using runtime_test::NotifyComponentC; + + auto reg = ecsact::core::registry("NotifyOnRemove"); + + auto entity = reg.create_entity(); + + auto notify_comp_a = NotifyComponentA{.val = 0}; + auto notify_comp_b = NotifyComponentB{.val = 0}; + auto notify_comp_c = NotifyComponentC{.val = 0}; + + auto exec_options = ecsact::core::execution_options{}; + auto evc = ecsact::core::execution_events_collector<>{}; + + exec_options.add_component(entity, ¬ify_comp_a); + exec_options.add_component(entity, ¬ify_comp_b); + exec_options.add_component(entity, ¬ify_comp_c); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::RemoveNotify::id), + runtime_test__RemoveNotify + ); + + auto error = reg.execute_systems(std::array{exec_options}, evc); + ASSERT_EQ(error, ECSACT_EXEC_SYS_OK); + reg.execute_systems(5); + auto updated_comp_a = reg.get_component(entity); + ASSERT_EQ(updated_comp_a.val, 0); + + exec_options.clear(); + exec_options.remove_component(entity, notify_comp_b.id); + error = reg.execute_systems(std::array{exec_options}, evc); + ASSERT_EQ(error, ECSACT_EXEC_SYS_OK); + + updated_comp_a = reg.get_component(entity); + ASSERT_EQ(updated_comp_a.val, 1); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::RemoveNotify::id), + nullptr + ); +} + +TEST(Core, NotifyOnSystemUpdate) { + using runtime_test::NotifyComponentA; + using runtime_test::TriggerTag; + using runtime_test::UpdateNotifyAdd; + + auto reg = ecsact::core::registry("NotifyOnSystemUpdate"); + + auto entity = reg.create_entity(); + + auto notify_comp_a = NotifyComponentA{.val = 0}; + auto trigger_tag = TriggerTag{}; + + auto exec_options = ecsact::core::execution_options{}; + auto evc = ecsact::core::execution_events_collector<>{}; + + exec_options.add_component(entity, ¬ify_comp_a); + exec_options.add_component(entity, &trigger_tag); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::TriggerUpdateNotify::id + ), + runtime_test__TriggerUpdateNotify + ); + + ecsact_set_system_execution_impl( + ecsact_id_cast(runtime_test::UpdateNotify::id), + runtime_test__UpdateNotify + ); + + auto event_happened = false; + evc.set_init_callback( + [&](ecsact_entity_id entity_id, const UpdateNotifyAdd& component) { + event_happened = true; + } + ); + + auto error = reg.execute_systems(std::array{exec_options}, evc); + ASSERT_EQ(error, ECSACT_EXEC_SYS_OK); + notify_comp_a = reg.get_component(entity); + ASSERT_EQ(notify_comp_a.val, 1); + + reg.execute_systems(5); + notify_comp_a = reg.get_component(entity); + ASSERT_EQ(notify_comp_a.val, 1); + + EXPECT_TRUE(event_happened) << "Init event did not happen"; +} diff --git a/test/runtime_test.ecsact b/test/runtime_test.ecsact index 6747239..23570ea 100644 --- a/test/runtime_test.ecsact +++ b/test/runtime_test.ecsact @@ -190,3 +190,51 @@ system LazyParentSystem(lazy) { readwrite TestLazySystemComponentB; } } + +// Notify systems + +component NotifyComponentA { + i8 val; +} +component NotifyComponentB { + i8 val; +} +component NotifyComponentC { + i8 val; +} + +system InitNotify { + readwrite NotifyComponentA; + readonly NotifyComponentB; + readonly NotifyComponentC; + notify oninit; +} + +system InitNotifySelective { + readwrite NotifyComponentA; + readonly NotifyComponentB; + readonly NotifyComponentC; + notify oninit; +} + +component TriggerTag; +component UpdateNotifyAdd; + +system TriggerUpdateNotify{ + readwrite NotifyComponentA; + removes TriggerTag; +} + +system UpdateNotify { + readwrite NotifyComponentA; + adds UpdateNotifyAdd; + notify onupdate; +} + +system RemoveNotify { + readwrite NotifyComponentA; + readonly NotifyComponentC; + notify { + onremove NotifyComponentB; + } +}