Skip to content

Commit

Permalink
feat: add onchange for systems
Browse files Browse the repository at this point in the history
  • Loading branch information
Kelwan committed May 22, 2024
1 parent fa98277 commit 115874a
Show file tree
Hide file tree
Showing 13 changed files with 419 additions and 26 deletions.
7 changes: 4 additions & 3 deletions ecsact/entt/detail/apply_pending.hh
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ auto apply_pending_add(::entt::registry& registry) -> void {
registry.emplace<C>(entity);
});
} else {
registry.view<pending_add<C>>().each(
registry.view<pending_add<C>>().each( //
[&](auto entity, const pending_add<C>& comp) {
registry.emplace<C>(entity, comp.value);
registry.emplace<beforechange_storage<C>>(entity, comp.value, false);
registry
.emplace<exec_beforechange_storage<C>>(entity, comp.value, false);
}
);
}
Expand All @@ -27,7 +28,7 @@ template<typename C>
auto apply_pending_remove(::entt::registry& registry) -> void {
registry.view<pending_remove<C>>().each([&](auto entity) {
if constexpr(!std::is_empty_v<C>) {
registry.erase<beforechange_storage<C>>(entity);
registry.erase<exec_beforechange_storage<C>>(entity);
}
registry.erase<C>(entity);
});
Expand Down
22 changes: 21 additions & 1 deletion ecsact/entt/detail/internal_markers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ struct beforeremove_storage<C> {

template<typename C>
requires(!std::is_empty_v<C>)
struct beforechange_storage {
struct exec_beforechange_storage {
C value;
bool has_update_occurred = false;
};

template<typename C>
requires(!std::is_empty_v<C>)
struct exec_itr_beforechange_storage {
C value;
};

template<typename C>
struct pending_add;

Expand Down Expand Up @@ -107,4 +113,18 @@ auto remove_system_markers_if_needed( //
)");
}

template<typename C>
auto add_exec_itr_beforechange_if_needed( //
::entt::registry&,
ecsact::entt::entity_id
) -> void {
static_assert(system_markers_unimplemented_by_codegen<C>, R"(
-----------------------------------------------------------------------------
| (!) CODEGEN ERROR |
| `add_exec_itr_beforechange_if_needed<>` template specialization cannot be found |
| This is typically generated by ecsact_rt_entt_codegen. |
-----------------------------------------------------------------------------
)");
}

} // namespace ecsact::entt::detail
43 changes: 35 additions & 8 deletions ecsact/entt/wrapper/core.hh
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ inline auto add_component( //
if constexpr(std::is_empty_v<C>) {
reg.emplace<C>(entity);
} else {
reg.emplace<detail::beforechange_storage<C>>(
reg.emplace<detail::exec_beforechange_storage<C>>(
entity,
*static_cast<const C*>(component_data),
false
Expand All @@ -68,6 +68,7 @@ inline auto add_component( //
}

ecsact::entt::detail::add_system_markers_if_needed<C>(reg, entity);
ecsact::entt::detail::add_exec_itr_beforechange_if_needed<C>(reg, entity);
}

return err;
Expand Down Expand Up @@ -96,14 +97,15 @@ inline auto add_component_exec_options( //
if constexpr(std::is_empty_v<C>) {
reg.emplace<C>(entity);
} else {
reg.emplace<detail::beforechange_storage<C>>(
reg.emplace<detail::exec_beforechange_storage<C>>(
entity,
*static_cast<const C*>(component_data)
);
reg.emplace<C>(entity, *static_cast<const C*>(component_data));
}
reg.template emplace_or_replace<component_added<C>>(entity);
ecsact::entt::detail::add_system_markers_if_needed<C>(reg, entity);
ecsact::entt::detail::add_exec_itr_beforechange_if_needed<C>(reg, entity);
}

return err;
Expand Down Expand Up @@ -172,7 +174,7 @@ auto remove_component(

reg.remove<C>(entity);
if constexpr(!std::is_empty_v<C>) {
reg.remove<detail::beforechange_storage<C>>(entity);
reg.remove<detail::exec_beforechange_storage<C>>(entity);
}
reg.template remove<component_added<C>>(entity);
reg.template remove<component_updated<C>>(entity);
Expand Down Expand Up @@ -205,7 +207,7 @@ auto remove_component_exec_options(
reg.template emplace_or_replace<component_removed<C>>(entity);

if constexpr(!std::is_empty_v<C>) {
reg.template remove<detail::beforechange_storage<C>>(entity);
reg.template remove<detail::exec_beforechange_storage<C>>(entity);
}

ecsact::entt::detail::remove_system_markers_if_needed<C>(reg, entity);
Expand Down Expand Up @@ -294,7 +296,7 @@ auto _trigger_update_component_event(
ecsact::entt::detail::execution_events_collector& events_collector
) -> void {
using ecsact::entt::component_updated;
using ecsact::entt::detail::beforechange_storage;
using ecsact::entt::detail::exec_beforechange_storage;

if(!events_collector.has_update_callback()) {
return;
Expand All @@ -304,12 +306,13 @@ auto _trigger_update_component_event(
if constexpr(!C::transient && !std::is_empty_v<C>) {
::entt::basic_view changed_view{
reg.template storage<C>(),
reg.template storage<beforechange_storage<C>>(),
reg.template storage<exec_beforechange_storage<C>>(),
reg.template storage<component_updated<C>>(),
};

for(ecsact::entt::entity_id entity : changed_view) {
auto& before = changed_view.template get<beforechange_storage<C>>(entity);
auto& before =
changed_view.template get<exec_beforechange_storage<C>>(entity);
auto& current = changed_view.template get<C>(entity);
before.has_update_occurred = false;

Expand Down Expand Up @@ -403,9 +406,33 @@ inline auto prepare_component(ecsact_registry_id registry_id) -> void {
reg.template storage<component_removed<C>>();

if constexpr(!std::is_empty_v<C>) {
reg.storage<detail::beforechange_storage<C>>();
reg.storage<detail::exec_beforechange_storage<C>>();
reg.template storage<component_updated<C>>();
}
}

template<typename C, typename V>
auto has_component_changed(entt::entity_id entity, V& view) -> bool {
using detail::exec_itr_beforechange_storage;

const auto& current_comp = view.template get<C>(entity);
const auto& before_comp =
view.template get<exec_itr_beforechange_storage<C>>(entity);

if(before_comp.value != current_comp) {
return true;
}
return false;
}

template<typename C>
auto update_exec_itr_beforechange(entt::entity_id entity, ::entt::registry& reg)
-> void {
auto comp = reg.get<C>(entity);
auto& beforechange_comp =
reg.get<detail::exec_itr_beforechange_storage<C>>(entity);

beforechange_comp.value = comp;
}

} // namespace ecsact::entt::wrapper::core
10 changes: 4 additions & 6 deletions ecsact/entt/wrapper/dynamic.hh
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ auto context_add(
) -> void {
using ecsact::entt::component_added;
using ecsact::entt::component_removed;
using ecsact::entt::detail::beforechange_storage;
using ecsact::entt::detail::beforeremove_storage;
using ecsact::entt::detail::exec_beforechange_storage;
using ecsact::entt::detail::pending_add;

assert(ecsact_id_cast<ecsact_component_like_id>(C::id) == component_id);
Expand All @@ -34,7 +34,6 @@ auto context_add(
} else {
const C* component = static_cast<const C*>(component_data);
registry.template emplace_or_replace<pending_add<C>>(entity, *component);

registry.template remove<beforeremove_storage<C>>(entity);
}

Expand All @@ -54,8 +53,6 @@ auto component_add_trivial(
) -> void {
using ecsact::entt::component_added;
using ecsact::entt::component_removed;
using ecsact::entt::detail::beforechange_storage;
using ecsact::entt::detail::beforeremove_storage;
using ecsact::entt::detail::pending_add;

registry.template emplace_or_replace<pending_add<C>>(entity_id);
Expand Down Expand Up @@ -146,7 +143,7 @@ auto context_update(
const void* in_component_data
) -> void {
using ecsact::entt::component_updated;
using ecsact::entt::detail::beforechange_storage;
using ecsact::entt::detail::exec_beforechange_storage;
// TODO(Kelwan): for remove, beforeremove_storage

auto entity = context->entity;
Expand All @@ -155,7 +152,8 @@ auto context_update(
const auto& in_component = *static_cast<const C*>(in_component_data);

auto& current_component = registry.template get<C>(entity);
auto& beforechange = registry.template get<beforechange_storage<C>>(entity);
auto& beforechange =
registry.template get<exec_beforechange_storage<C>>(entity);
if(!beforechange.has_update_occurred) {
beforechange.value = current_component;
beforechange.has_update_occurred = true;
Expand Down
2 changes: 2 additions & 0 deletions rt_entt_codegen/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ _CORE_CODEGEN_METHODS = {
],
"system_markers": [
"//rt_entt_codegen/shared:sorting",
"//rt_entt_codegen/shared:system_util",
],
"system_notify": ["//rt_entt_codegen/shared:system_util"],
"update_beforechange": [],
}

[cc_library(
Expand Down
10 changes: 10 additions & 0 deletions rt_entt_codegen/core/core.hh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ auto print_system_marker_remove_fn(
const ecsact_entt_details& details
) -> void;

auto print_add_sys_beforestorage_fn(
codegen_plugin_context& ctx,
const ecsact_entt_details& details
) -> void;

auto print_cleanup_system_notifies(
codegen_plugin_context& ctx,
const ecsact_entt_details& details
Expand All @@ -76,4 +81,9 @@ auto print_entity_match_fn(
const ecsact_entt_details& details
) -> void;

auto print_update_all_beforechange_storage(
codegen_plugin_context& ctx,
const ecsact_entt_details& details
) -> void;

} // namespace ecsact::rt_entt_codegen::core
7 changes: 5 additions & 2 deletions rt_entt_codegen/core/execute_systems.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ auto ecsact::rt_entt_codegen::core::print_execute_systems( //
}
}

ctx.write("\nupdate_all_beforechange_storage(registry_id);\n");
ctx.write("cleanup_system_notifies(registry_id);\n");

ctx.indentation -= 1;
ctx.write("\n}\n\n");

Expand All @@ -88,9 +91,9 @@ auto ecsact::rt_entt_codegen::core::print_execute_systems( //
"trigger_component_events_all(registry_id, events_collector);\n\n"
);
});
ctx.write("cleanup_component_events(registry_id);\n");
ctx.write("cleanup_system_notifies(registry_id);\n");
});

ctx.write("cleanup_component_events(registry_id);\n");

ctx.write("return ECSACT_EXEC_SYS_OK;");
}
48 changes: 48 additions & 0 deletions rt_entt_codegen/core/system_markers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ecsact/lang-support/lang-cc.hh"
#include "ecsact/cpp_codegen_plugin_util.hh"
#include "rt_entt_codegen/shared/sorting.hh"
#include "rt_entt_codegen/shared/system_util.hh"

using ecsact::cpp_codegen_plugin_util::block;
using ecsact::cpp_codegen_plugin_util::method_printer;
Expand Down Expand Up @@ -93,3 +94,50 @@ auto ecsact::rt_entt_codegen::core::print_system_marker_remove_fn(
ctx.write("//TODO\n");
}
}

auto ecsact::rt_entt_codegen::core::print_add_sys_beforestorage_fn(
codegen_plugin_context& ctx,
const ecsact_entt_details& details
) -> void {
using cc_lang_support::cpp_identifier;
using ecsact::meta::decl_full_name;

auto already_printed_ = std::set<ecsact_component_id>{};

for(auto comp_id : details.all_components) {
auto comp_name = cpp_identifier(decl_full_name(comp_id));

ctx.write("template<>\n");
auto printer =
method_printer{
ctx,
std::format(
"ecsact::entt::detail::add_exec_itr_beforechange_if_needed< {}>",
comp_name
)
}
.parameter("::entt::registry&", "reg")
.parameter("ecsact::entt::entity_id", "entity")
.return_type("void");

for(auto system_id : details.all_systems) {
auto notify_settings = ecsact::meta::system_notify_settings(system_id);

for(auto const [comp_id_to_compare, notify_setting] : notify_settings) {
if(comp_id == static_cast<ecsact_component_id>(comp_id_to_compare)) {
if(notify_setting == ECSACT_SYS_NOTIFY_ONCHANGE) {
if(already_printed_.contains(comp_id)) {
break;
}
already_printed_.insert(comp_id);
ctx.write(std::format( //
"reg.emplace<exec_itr_beforechange_storage<{}>>(entity);\n",
comp_name
));
break;
}
}
}
}
}
}
54 changes: 54 additions & 0 deletions rt_entt_codegen/core/update_beforechange.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "core.hh"

#include <format>

#include "ecsact/lang-support/lang-cc.hh"
#include "rt_entt_codegen/shared/util.hh"
#include "ecsact/runtime/common.h"
#include "ecsact/cpp_codegen_plugin_util.hh"

auto ecsact::rt_entt_codegen::core::print_update_all_beforechange_storage(
codegen_plugin_context& ctx,
const ecsact_entt_details& details
) -> void {
using ecsact::cc_lang_support::c_identifier;
using ecsact::cc_lang_support::cpp_identifier;
using ecsact::cpp_codegen_plugin_util::block;
using ecsact::cpp_codegen_plugin_util::method_printer;
using ecsact::meta::decl_full_name;

auto printer = //
method_printer{ctx, "update_all_beforechange_storage"}
.parameter("ecsact_registry_id", "registry_id")
.return_type("void");

ctx.write("auto& reg = ecsact::entt::get_registry(registry_id);\n\n");

for(auto comp_id : details.all_components) {
if(ecsact::meta::get_field_ids(comp_id).empty()) {
continue;
}

auto comp_name = c_identifier(decl_full_name((comp_id)));
auto cpp_comp_name = cpp_identifier(decl_full_name(comp_id));
auto comp_change_name = std::format( //
"ecsact::entt::detail::exec_itr_beforechange_storage<{}>",
cpp_comp_name
);

auto view_name = std::format("{}_view", comp_name);
auto comp_list = std::format("{}, {}", cpp_comp_name, comp_change_name);

ctx.write( //
std::format("auto {} = reg.view<{}>();\n", view_name, comp_list)
);

block(ctx, std::format("for(auto entity: {})", view_name), [&]() {
ctx.write(std::format(
"ecsact::entt::wrapper::core::update_exec_itr_beforechange<{}>(entity, "
"reg);\n",
cpp_comp_name
));
});
}
}
Loading

0 comments on commit 115874a

Please # to comment.