Skip to content

feat: sorted lazy systems #95

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions ecsact/entt/detail/internal_markers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include <cstdint>
#include <type_traits>
#include <concepts>
#include "entt/entt.hpp"
#include "ecsact/entt/entity.hh"
#include "ecsact/runtime/common.h"

namespace ecsact::entt::detail {
Expand Down Expand Up @@ -63,9 +64,43 @@ struct created_entity {
struct destroyed_entity {};

template<typename S>
struct system_sorted;
struct system_sorted {
std::uint64_t hash = 0;
friend auto operator<=>(const system_sorted&, const system_sorted&) = default;
};

template<typename S>
struct pending_lazy_execution {};

template<typename>
constexpr bool system_markers_unimplemented_by_codegen = false;

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

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

} // namespace ecsact::entt::detail
17 changes: 16 additions & 1 deletion ecsact/entt/execution.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#include <unordered_map>
#include <cassert>
#include <span>
#include <type_traits>
#include "ecsact/runtime/common.h"
#include "ecsact/entt/entity.hh"
#include "entt/entity/registry.hpp"
#include "ecsact/entt/detail/globals.hh"

Expand Down Expand Up @@ -142,4 +142,19 @@ auto prepare_system_like(::entt::registry&) -> void {
)");
}

/**
* Checks entity 'matches' a system i.e. the system will execute on the provided
* entity.
*/
template<typename SystemLike>
auto entity_matches_system(::entt::registry&, ecsact::entt::entity_id) -> bool {
static_assert(detail::unimplemented_by_codegen<SystemLike>, R"(
-----------------------------------------------------------------------------
| (!) CODEGEN ERROR |
| `entity_matches_system<>` template specialization cannot be found. This is |
| typically generated by ecsact_rt_entt_codegen. |
-----------------------------------------------------------------------------
)");
}

} // namespace ecsact::entt
6 changes: 6 additions & 0 deletions ecsact/entt/wrapper/core.hh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ inline auto add_component( //
);
reg.emplace<C>(entity, *static_cast<const C*>(component_data));
}

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

return err;
Expand Down Expand Up @@ -100,6 +102,7 @@ inline auto add_component_exec_options( //
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);
}

return err;
Expand Down Expand Up @@ -173,6 +176,7 @@ auto remove_component(
reg.template remove<component_added<C>>(entity);
reg.template remove<component_changed<C>>(entity);
reg.template emplace_or_replace<component_removed<C>>(entity);
ecsact::entt::detail::remove_system_markers_if_needed<C>(reg, entity);
}

template<typename C>
Expand Down Expand Up @@ -202,6 +206,8 @@ auto remove_component_exec_options(
if constexpr(!std::is_empty_v<C>) {
reg.template remove<detail::beforechange_storage<C>>(entity);
}

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

inline auto _trigger_create_entity_events(
Expand Down
13 changes: 11 additions & 2 deletions rt_entt_codegen/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,25 @@ cc_library(
_CORE_CODEGEN_METHODS = {
"execute_systems": [],
"create_registry": [],
"entity_matches": [
"//rt_entt_codegen/shared:sorting",
],
"init_registry_storage": [],
"events": [],
"print_sys_exec": [
"//rt_entt_codegen/shared:comps_with_caps",
"//rt_entt_codegen/shared:sorting",
"@entt//:entt",
"@ecsact_rt_entt//:lib",
],
"check_error_template_specializations": [],
"check_error": [],
"execution_options": [],
"sorting_components": [],
"sorting_components": [
"//rt_entt_codegen/shared:sorting",
],
"system_markers": [
"//rt_entt_codegen/shared:sorting",
],
}

[cc_library(
Expand Down
15 changes: 15 additions & 0 deletions rt_entt_codegen/core/core.hh
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,19 @@ auto print_entity_sorting_components( //
const ecsact_entt_details& details
) -> void;

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

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

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

} // namespace ecsact::rt_entt_codegen::core
60 changes: 60 additions & 0 deletions rt_entt_codegen/core/entity_matches.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "rt_entt_codegen/core/core.hh"

#include <ranges>
#include <format>
#include "ecsact/runtime/meta.hh"
#include "ecsact/lang-support/lang-cc.hh"
#include "ecsact/cpp_codegen_plugin_util.hh"
#include "rt_entt_codegen/shared/util.hh"

using ecsact::cpp_codegen_plugin_util::block;
using ecsact::cpp_codegen_plugin_util::method_printer;

auto ecsact::rt_entt_codegen::core::print_entity_match_fn(
codegen_plugin_context& ctx,
const ecsact_entt_details& details
) -> void {
using ecsact::rt_entt_codegen::util::decl_cpp_ident;
using std::views::transform;

for(auto sys_id : details.all_systems) {
auto sys_details = ecsact_entt_system_details::from_system_like(
ecsact_id_cast<ecsact_system_like_id>(sys_id)
);
auto system_name = ecsact::meta::decl_full_name(sys_id);
auto system_cpp_ident = cc_lang_support::cpp_identifier(system_name);
auto method_name =
"ecsact::entt::entity_matches_system<" + system_cpp_ident + ">";

ctx.write("template<>\n");
auto printer = //
method_printer{ctx, method_name}
.parameter("::entt::registry&", "reg")
.parameter("ecsact::entt::entity_id", "entity")
.return_type("bool");

auto get_comps_str = util::comma_delim(
sys_details.get_comps |
transform(decl_cpp_ident<ecsact_component_like_id>)
);

block(ctx, std::format("if(!reg.all_of<{}>(entity))", get_comps_str), [&] {
ctx.write("return false;");
});

if(!sys_details.exclude_comps.empty()) {
auto exclude_comps_str = util::comma_delim(
sys_details.exclude_comps |
transform(decl_cpp_ident<ecsact_component_like_id>)
);

block(
ctx,
std::format("if(reg.any_of<{}>(entity))", exclude_comps_str),
[&] { ctx.write("return false;"); }
);
}

ctx.write("return true;\n");
}
}
98 changes: 39 additions & 59 deletions rt_entt_codegen/core/print_sys_exec.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#include "core.hh"

#include <concepts>
#include <fenv.h>
#include <ranges>
#include <set>
#include <string>
#include <type_traits>
#include <unordered_map>
Expand All @@ -17,6 +14,7 @@
#include "rt_entt_codegen/shared/ecsact_entt_details.hh"
#include "rt_entt_codegen/shared/util.hh"
#include "rt_entt_codegen/shared/comps_with_caps.hh"
#include "rt_entt_codegen/shared/sorting.hh"

using capability_t =
std::unordered_map<ecsact_component_like_id, ecsact_system_capability>;
Expand All @@ -26,6 +24,7 @@ concept system_or_action =
std::same_as<T, ecsact_system_id> || std::same_as<T, ecsact_action_id>;

using ecsact::rt_entt_codegen::system_comps_with_caps;
using ecsact::rt_entt_codegen::system_needs_sorted_entities;

template<system_or_action T>
static auto print_sys_exec_ctx_action(
Expand Down Expand Up @@ -483,58 +482,6 @@ static auto print_sys_exec_ctx_other(
ctx.write("return nullptr;");
}

static auto comma_delim(auto&& range) -> std::string {
auto result = std::string{};

for(auto str : range) {
result += str + ", ";
}

if(result.ends_with(", ")) {
result = result.substr(0, result.size() - 2);
}

return result;
}

static auto make_view( //
ecsact::codegen_plugin_context& ctx,
auto&& view_var_name,
auto&& registry_var_name,
const ecsact::rt_entt_codegen::ecsact_entt_system_details& details,
std::vector<std::string> additional_components = {}
) -> void {
using namespace std::string_literals;
using ecsact::rt_entt_codegen::util::decl_cpp_ident;
using std::views::transform;

ctx.write("auto ", view_var_name, " = ", registry_var_name, ".view<");

ctx.write(comma_delim(
details.get_comps | transform(decl_cpp_ident<ecsact_component_like_id>)
));

if(!additional_components.empty()) {
ctx.write(", ");
ctx.write(comma_delim(additional_components));
}

ctx.write(">(");

if(!details.exclude_comps.empty()) {
ctx.write(
"::entt::exclude<",
comma_delim(
details.exclude_comps |
transform(decl_cpp_ident<ecsact_component_like_id>)
),
">"
);
}

ctx.write(");\n");
}

template<typename SystemLikeID>
static auto print_apply_pendings(
ecsact::codegen_plugin_context& ctx,
Expand Down Expand Up @@ -634,6 +581,11 @@ static auto print_ecsact_entt_system_details(
options.system_name
);

auto system_sorting_struct_name = std::format(
"::ecsact::entt::detail::system_sorted<{}>",
options.system_name
);

auto additional_view_components = std::vector<std::string>{};

if(lazy_iteration_rate > 0) {
Expand All @@ -647,13 +599,22 @@ static auto print_ecsact_entt_system_details(
additional_view_components.push_back(pending_lazy_exec_struct);
}

make_view(
if(system_needs_sorted_entities(options.sys_like_id, details)) {
additional_view_components.push_back(system_sorting_struct_name);
}

ecsact::rt_entt_codegen::util::make_view(
ctx,
"view",
options.registry_var_name,
details,
additional_view_components
);

if(system_needs_sorted_entities(options.sys_like_id, details)) {
ctx.write("view.use<", system_sorting_struct_name, ">();\n");
}

block(ctx, "struct : ecsact_system_execution_context ", [&] {
ctx.write("decltype(view)* view;\n");

Expand Down Expand Up @@ -814,7 +775,21 @@ static auto print_ecsact_entt_system_details(
);
ctx.write("assert(iteration_count_ <= lazy_iteration_rate_);\n");
block(ctx, "if(iteration_count_ < lazy_iteration_rate_)", [&] {
make_view(
ctx.write(
"_recalc_sorting_hash<",
options.system_name,
">(",
options.registry_var_name,
");\n"
);
ctx.write(
options.registry_var_name,
".sort<",
system_sorting_struct_name,
">([](const auto& a, const auto& b) { return a.hash < b.hash; });\n"
);

ecsact::rt_entt_codegen::util::make_view(
ctx,
"view_no_pending_lazy_",
options.registry_var_name,
Expand Down Expand Up @@ -914,7 +889,12 @@ static auto print_other_contexts(
auto other_details =
ecsact_entt_system_details::from_capabilities(assoc_detail.capabilities);

make_view(ctx, view_name, "registry", other_details);
ecsact::rt_entt_codegen::util::make_view(
ctx,
view_name,
"registry",
other_details
);

block(ctx, "struct " + struct_header, [&] {
using namespace std::string_literals;
Expand Down Expand Up @@ -1011,7 +991,7 @@ static auto print_trivial_system_like(
.parameter("ecsact_system_execution_context*", "parent_context")
.return_type("void");

make_view(ctx, "view", "registry", details);
ecsact::rt_entt_codegen::util::make_view(ctx, "view", "registry", details);

block(ctx, "for(auto entity : view)", [&] {
for(auto&& [comp_id, capability] : sys_capabilities) {
Expand Down
Loading