Skip to content

Commit 1356b93

Browse files
authored
feat: sorted lazy systems (#95)
1 parent b94cfcb commit 1356b93

18 files changed

+674
-132
lines changed

ecsact/entt/detail/internal_markers.hh

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
#include <cstdint>
44
#include <type_traits>
5-
#include <concepts>
5+
#include "entt/entt.hpp"
6+
#include "ecsact/entt/entity.hh"
67
#include "ecsact/runtime/common.h"
78

89
namespace ecsact::entt::detail {
@@ -63,9 +64,43 @@ struct created_entity {
6364
struct destroyed_entity {};
6465

6566
template<typename S>
66-
struct system_sorted;
67+
struct system_sorted {
68+
std::uint64_t hash = 0;
69+
friend auto operator<=>(const system_sorted&, const system_sorted&) = default;
70+
};
6771

6872
template<typename S>
6973
struct pending_lazy_execution {};
7074

75+
template<typename>
76+
constexpr bool system_markers_unimplemented_by_codegen = false;
77+
78+
template<typename C>
79+
auto add_system_markers_if_needed( //
80+
::entt::registry&,
81+
ecsact::entt::entity_id
82+
) -> void {
83+
static_assert(system_markers_unimplemented_by_codegen<C>, R"(
84+
-----------------------------------------------------------------------------
85+
| (!) CODEGEN ERROR |
86+
| `add_system_markers_if_needed<>` template specialization cannot be found. |
87+
| This is typically generated by ecsact_rt_entt_codegen. |
88+
-----------------------------------------------------------------------------
89+
)");
90+
}
91+
92+
template<typename C>
93+
auto remove_system_markers_if_needed( //
94+
::entt::registry&,
95+
ecsact::entt::entity_id
96+
) -> void {
97+
static_assert(system_markers_unimplemented_by_codegen<C>, R"(
98+
-----------------------------------------------------------------------------
99+
| (!) CODEGEN ERROR |
100+
| `remove_system_markers_if_needed<>` template specialization cannot be found |
101+
| This is typically generated by ecsact_rt_entt_codegen. |
102+
-----------------------------------------------------------------------------
103+
)");
104+
}
105+
71106
} // namespace ecsact::entt::detail

ecsact/entt/execution.hh

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#include <unordered_map>
55
#include <cassert>
66
#include <span>
7-
#include <type_traits>
87
#include "ecsact/runtime/common.h"
8+
#include "ecsact/entt/entity.hh"
99
#include "entt/entity/registry.hpp"
1010
#include "ecsact/entt/detail/globals.hh"
1111

@@ -142,4 +142,19 @@ auto prepare_system_like(::entt::registry&) -> void {
142142
)");
143143
}
144144

145+
/**
146+
* Checks entity 'matches' a system i.e. the system will execute on the provided
147+
* entity.
148+
*/
149+
template<typename SystemLike>
150+
auto entity_matches_system(::entt::registry&, ecsact::entt::entity_id) -> bool {
151+
static_assert(detail::unimplemented_by_codegen<SystemLike>, R"(
152+
-----------------------------------------------------------------------------
153+
| (!) CODEGEN ERROR |
154+
| `entity_matches_system<>` template specialization cannot be found. This is |
155+
| typically generated by ecsact_rt_entt_codegen. |
156+
-----------------------------------------------------------------------------
157+
)");
158+
}
159+
145160
} // namespace ecsact::entt

ecsact/entt/wrapper/core.hh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ inline auto add_component( //
6565
);
6666
reg.emplace<C>(entity, *static_cast<const C*>(component_data));
6767
}
68+
69+
ecsact::entt::detail::add_system_markers_if_needed<C>(reg, entity);
6870
}
6971

7072
return err;
@@ -100,6 +102,7 @@ inline auto add_component_exec_options( //
100102
reg.emplace<C>(entity, *static_cast<const C*>(component_data));
101103
}
102104
reg.template emplace_or_replace<component_added<C>>(entity);
105+
ecsact::entt::detail::add_system_markers_if_needed<C>(reg, entity);
103106
}
104107

105108
return err;
@@ -173,6 +176,7 @@ auto remove_component(
173176
reg.template remove<component_added<C>>(entity);
174177
reg.template remove<component_changed<C>>(entity);
175178
reg.template emplace_or_replace<component_removed<C>>(entity);
179+
ecsact::entt::detail::remove_system_markers_if_needed<C>(reg, entity);
176180
}
177181

178182
template<typename C>
@@ -202,6 +206,8 @@ auto remove_component_exec_options(
202206
if constexpr(!std::is_empty_v<C>) {
203207
reg.template remove<detail::beforechange_storage<C>>(entity);
204208
}
209+
210+
ecsact::entt::detail::remove_system_markers_if_needed<C>(reg, entity);
205211
}
206212

207213
inline auto _trigger_create_entity_events(

rt_entt_codegen/core/BUILD.bazel

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,25 @@ cc_library(
1313
_CORE_CODEGEN_METHODS = {
1414
"execute_systems": [],
1515
"create_registry": [],
16+
"entity_matches": [
17+
"//rt_entt_codegen/shared:sorting",
18+
],
1619
"init_registry_storage": [],
1720
"events": [],
1821
"print_sys_exec": [
1922
"//rt_entt_codegen/shared:comps_with_caps",
23+
"//rt_entt_codegen/shared:sorting",
2024
"@entt//:entt",
2125
"@ecsact_rt_entt//:lib",
2226
],
23-
"check_error_template_specializations": [],
27+
"check_error": [],
2428
"execution_options": [],
25-
"sorting_components": [],
29+
"sorting_components": [
30+
"//rt_entt_codegen/shared:sorting",
31+
],
32+
"system_markers": [
33+
"//rt_entt_codegen/shared:sorting",
34+
],
2635
}
2736

2837
[cc_library(

rt_entt_codegen/core/core.hh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,19 @@ auto print_entity_sorting_components( //
5656
const ecsact_entt_details& details
5757
) -> void;
5858

59+
auto print_system_marker_add_fn(
60+
codegen_plugin_context& ctx,
61+
const ecsact_entt_details& details
62+
) -> void;
63+
64+
auto print_system_marker_remove_fn(
65+
codegen_plugin_context& ctx,
66+
const ecsact_entt_details& details
67+
) -> void;
68+
69+
auto print_entity_match_fn(
70+
codegen_plugin_context& ctx,
71+
const ecsact_entt_details& details
72+
) -> void;
73+
5974
} // namespace ecsact::rt_entt_codegen::core
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "rt_entt_codegen/core/core.hh"
2+
3+
#include <ranges>
4+
#include <format>
5+
#include "ecsact/runtime/meta.hh"
6+
#include "ecsact/lang-support/lang-cc.hh"
7+
#include "ecsact/cpp_codegen_plugin_util.hh"
8+
#include "rt_entt_codegen/shared/util.hh"
9+
10+
using ecsact::cpp_codegen_plugin_util::block;
11+
using ecsact::cpp_codegen_plugin_util::method_printer;
12+
13+
auto ecsact::rt_entt_codegen::core::print_entity_match_fn(
14+
codegen_plugin_context& ctx,
15+
const ecsact_entt_details& details
16+
) -> void {
17+
using ecsact::rt_entt_codegen::util::decl_cpp_ident;
18+
using std::views::transform;
19+
20+
for(auto sys_id : details.all_systems) {
21+
auto sys_details = ecsact_entt_system_details::from_system_like(
22+
ecsact_id_cast<ecsact_system_like_id>(sys_id)
23+
);
24+
auto system_name = ecsact::meta::decl_full_name(sys_id);
25+
auto system_cpp_ident = cc_lang_support::cpp_identifier(system_name);
26+
auto method_name =
27+
"ecsact::entt::entity_matches_system<" + system_cpp_ident + ">";
28+
29+
ctx.write("template<>\n");
30+
auto printer = //
31+
method_printer{ctx, method_name}
32+
.parameter("::entt::registry&", "reg")
33+
.parameter("ecsact::entt::entity_id", "entity")
34+
.return_type("bool");
35+
36+
auto get_comps_str = util::comma_delim(
37+
sys_details.get_comps |
38+
transform(decl_cpp_ident<ecsact_component_like_id>)
39+
);
40+
41+
block(ctx, std::format("if(!reg.all_of<{}>(entity))", get_comps_str), [&] {
42+
ctx.write("return false;");
43+
});
44+
45+
if(!sys_details.exclude_comps.empty()) {
46+
auto exclude_comps_str = util::comma_delim(
47+
sys_details.exclude_comps |
48+
transform(decl_cpp_ident<ecsact_component_like_id>)
49+
);
50+
51+
block(
52+
ctx,
53+
std::format("if(reg.any_of<{}>(entity))", exclude_comps_str),
54+
[&] { ctx.write("return false;"); }
55+
);
56+
}
57+
58+
ctx.write("return true;\n");
59+
}
60+
}

rt_entt_codegen/core/print_sys_exec.cc

Lines changed: 39 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
#include "core.hh"
22

3-
#include <concepts>
4-
#include <fenv.h>
53
#include <ranges>
6-
#include <set>
74
#include <string>
85
#include <type_traits>
96
#include <unordered_map>
@@ -17,6 +14,7 @@
1714
#include "rt_entt_codegen/shared/ecsact_entt_details.hh"
1815
#include "rt_entt_codegen/shared/util.hh"
1916
#include "rt_entt_codegen/shared/comps_with_caps.hh"
17+
#include "rt_entt_codegen/shared/sorting.hh"
2018

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

2826
using ecsact::rt_entt_codegen::system_comps_with_caps;
27+
using ecsact::rt_entt_codegen::system_needs_sorted_entities;
2928

3029
template<system_or_action T>
3130
static auto print_sys_exec_ctx_action(
@@ -483,58 +482,6 @@ static auto print_sys_exec_ctx_other(
483482
ctx.write("return nullptr;");
484483
}
485484

486-
static auto comma_delim(auto&& range) -> std::string {
487-
auto result = std::string{};
488-
489-
for(auto str : range) {
490-
result += str + ", ";
491-
}
492-
493-
if(result.ends_with(", ")) {
494-
result = result.substr(0, result.size() - 2);
495-
}
496-
497-
return result;
498-
}
499-
500-
static auto make_view( //
501-
ecsact::codegen_plugin_context& ctx,
502-
auto&& view_var_name,
503-
auto&& registry_var_name,
504-
const ecsact::rt_entt_codegen::ecsact_entt_system_details& details,
505-
std::vector<std::string> additional_components = {}
506-
) -> void {
507-
using namespace std::string_literals;
508-
using ecsact::rt_entt_codegen::util::decl_cpp_ident;
509-
using std::views::transform;
510-
511-
ctx.write("auto ", view_var_name, " = ", registry_var_name, ".view<");
512-
513-
ctx.write(comma_delim(
514-
details.get_comps | transform(decl_cpp_ident<ecsact_component_like_id>)
515-
));
516-
517-
if(!additional_components.empty()) {
518-
ctx.write(", ");
519-
ctx.write(comma_delim(additional_components));
520-
}
521-
522-
ctx.write(">(");
523-
524-
if(!details.exclude_comps.empty()) {
525-
ctx.write(
526-
"::entt::exclude<",
527-
comma_delim(
528-
details.exclude_comps |
529-
transform(decl_cpp_ident<ecsact_component_like_id>)
530-
),
531-
">"
532-
);
533-
}
534-
535-
ctx.write(");\n");
536-
}
537-
538485
template<typename SystemLikeID>
539486
static auto print_apply_pendings(
540487
ecsact::codegen_plugin_context& ctx,
@@ -634,6 +581,11 @@ static auto print_ecsact_entt_system_details(
634581
options.system_name
635582
);
636583

584+
auto system_sorting_struct_name = std::format(
585+
"::ecsact::entt::detail::system_sorted<{}>",
586+
options.system_name
587+
);
588+
637589
auto additional_view_components = std::vector<std::string>{};
638590

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

650-
make_view(
602+
if(system_needs_sorted_entities(options.sys_like_id, details)) {
603+
additional_view_components.push_back(system_sorting_struct_name);
604+
}
605+
606+
ecsact::rt_entt_codegen::util::make_view(
651607
ctx,
652608
"view",
653609
options.registry_var_name,
654610
details,
655611
additional_view_components
656612
);
613+
614+
if(system_needs_sorted_entities(options.sys_like_id, details)) {
615+
ctx.write("view.use<", system_sorting_struct_name, ">();\n");
616+
}
617+
657618
block(ctx, "struct : ecsact_system_execution_context ", [&] {
658619
ctx.write("decltype(view)* view;\n");
659620

@@ -814,7 +775,21 @@ static auto print_ecsact_entt_system_details(
814775
);
815776
ctx.write("assert(iteration_count_ <= lazy_iteration_rate_);\n");
816777
block(ctx, "if(iteration_count_ < lazy_iteration_rate_)", [&] {
817-
make_view(
778+
ctx.write(
779+
"_recalc_sorting_hash<",
780+
options.system_name,
781+
">(",
782+
options.registry_var_name,
783+
");\n"
784+
);
785+
ctx.write(
786+
options.registry_var_name,
787+
".sort<",
788+
system_sorting_struct_name,
789+
">([](const auto& a, const auto& b) { return a.hash < b.hash; });\n"
790+
);
791+
792+
ecsact::rt_entt_codegen::util::make_view(
818793
ctx,
819794
"view_no_pending_lazy_",
820795
options.registry_var_name,
@@ -914,7 +889,12 @@ static auto print_other_contexts(
914889
auto other_details =
915890
ecsact_entt_system_details::from_capabilities(assoc_detail.capabilities);
916891

917-
make_view(ctx, view_name, "registry", other_details);
892+
ecsact::rt_entt_codegen::util::make_view(
893+
ctx,
894+
view_name,
895+
"registry",
896+
other_details
897+
);
918898

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

1014-
make_view(ctx, "view", "registry", details);
994+
ecsact::rt_entt_codegen::util::make_view(ctx, "view", "registry", details);
1015995

1016996
block(ctx, "for(auto entity : view)", [&] {
1017997
for(auto&& [comp_id, capability] : sys_capabilities) {

0 commit comments

Comments
 (0)