From 258e0456bd69eaf1477178c83273940a78234106 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 7 Jun 2024 12:25:56 -0700 Subject: [PATCH 01/19] feat: use new assoc api --- MODULE.bazel | 11 ++++-- rt_entt_codegen/shared/comps_with_caps.hh | 24 ++++++------- rt_entt_codegen/shared/ecsact_entt_details.cc | 34 +++++++++---------- rt_entt_codegen/shared/ecsact_entt_details.hh | 6 ++-- rt_entt_codegen/shared/parallel.cc | 20 +++++------ runtime/index.bzl | 2 -- test/MODULE.bazel | 11 ++++-- 7 files changed, 56 insertions(+), 52 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index e2f94ab..c07e3c3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,15 +7,20 @@ module( bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.6.1") bazel_dep(name = "rules_ecsact", version = "0.5.2") -bazel_dep(name = "ecsact_runtime", version = "0.6.2") -bazel_dep(name = "ecsact_lang_cpp", version = "0.4.1") +bazel_dep(name = "ecsact_runtime", version = "0.6.5") +bazel_dep(name = "ecsact_lang_cpp", version = "0.4.3") bazel_dep(name = "boost.mp11", version = "1.83.0.bzl.1") bazel_dep(name = "entt", version = "3.12.2") bazel_dep(name = "ecsact_codegen", version = "0.2.0") -bazel_dep(name = "ecsact_cli", version = "0.3.9") +bazel_dep(name = "ecsact_cli", version = "0.3.10") bazel_dep(name = "xxhash", version = "0.8.2") bazel_dep(name = "googletest", version = "1.14.0.bcr.1") +local_path_override( + module_name = "ecsact_lang_cpp", + path = "../ecsact_lang_cpp", +) + bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) bazel_dep(name = "hedron_compile_commands", dev_dependency = True) git_override( diff --git a/rt_entt_codegen/shared/comps_with_caps.hh b/rt_entt_codegen/shared/comps_with_caps.hh index 087f9cb..6a64e34 100644 --- a/rt_entt_codegen/shared/comps_with_caps.hh +++ b/rt_entt_codegen/shared/comps_with_caps.hh @@ -21,21 +21,19 @@ auto get_all_deep_capabilities( // all_capabilities[comp_id] = static_cast( capability | all_capabilities[comp_id] ); + } - auto fields = - ecsact::meta::system_association_fields(system_like_id, comp_id); - for(auto field_id : fields) { - auto assoc_comps = ecsact::meta::system_association_capabilities( - system_like_id, - comp_id, - field_id - ); + auto assoc_ids = ecsact::meta::system_assoc_ids(system_like_id); + for(auto assoc_id : assoc_ids) { + auto assoc_comp = + ecsact::meta::system_assoc_component_id(system_like_id, assoc_id); + auto assoc_comp_caps = + ecsact::meta::system_assoc_capabilities(system_like_id, assoc_id); - for(auto&& [assoc_comp_id, assoc_comp_cap] : assoc_comps) { - all_capabilities[assoc_comp_id] = static_cast( - assoc_comp_cap | all_capabilities[assoc_comp_id] - ); - } + for(auto&& [comp_id, capability] : assoc_comp_caps) { + all_capabilities[comp_id] = static_cast( + capability | all_capabilities[comp_id] + ); } } diff --git a/rt_entt_codegen/shared/ecsact_entt_details.cc b/rt_entt_codegen/shared/ecsact_entt_details.cc index 219d02c..ee37ede 100644 --- a/rt_entt_codegen/shared/ecsact_entt_details.cc +++ b/rt_entt_codegen/shared/ecsact_entt_details.cc @@ -140,24 +140,22 @@ auto ecsact_entt_system_details::from_system_like( // fill_system_details(details, caps); - for(auto comp_id : details.readable_comps) { - auto fields = ecsact::meta::system_association_fields(sys_like_id, comp_id); - for(auto field_id : fields) { - auto assoc_comps = ecsact::meta::system_association_capabilities( - sys_like_id, - comp_id, - field_id - ); - - details.association_details.insert( - details.association_details.end(), - association_info{ - .component_id = comp_id, - .field_id = field_id, - .capabilities = assoc_comps, - } - ); - } + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto assoc_fields = + ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); + auto assoc_capabilities = + ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); + + details.association_details.insert( + details.association_details.end(), + association_info{ + assoc_comp_id, + assoc_fields, + assoc_capabilities, + } + ); } auto generate_ids = ecsact::meta::get_system_generates_ids(sys_like_id); diff --git a/rt_entt_codegen/shared/ecsact_entt_details.hh b/rt_entt_codegen/shared/ecsact_entt_details.hh index cdcd316..a140d21 100644 --- a/rt_entt_codegen/shared/ecsact_entt_details.hh +++ b/rt_entt_codegen/shared/ecsact_entt_details.hh @@ -8,9 +8,9 @@ namespace ecsact::rt_entt_codegen { struct association_info { - ecsact_component_like_id component_id; - ecsact_field_id field_id; - std::unordered_map + ecsact_component_like_id component_id; + std::vector field_ids; + std::vector> capabilities; }; diff --git a/rt_entt_codegen/shared/parallel.cc b/rt_entt_codegen/shared/parallel.cc index 7caa4d5..657199d 100644 --- a/rt_entt_codegen/shared/parallel.cc +++ b/rt_entt_codegen/shared/parallel.cc @@ -281,17 +281,17 @@ static auto loop_iterator( } } - auto other_fields = - ecsact::meta::system_association_fields(sys_like_id, comp_id); - - for(auto field_id : other_fields) { - auto other_capabilities = ecsact::meta::system_association_capabilities( - sys_like_id, - comp_id, - field_id - ); + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + + for(auto assoc_id : assoc_ids) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto assoc_field_ids = + ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); + auto assoc_capabilities = + ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); - for(const auto [other_comp_id, other_capability] : other_capabilities) { + for(const auto [other_comp_id, other_capability] : assoc_capabilities) { auto cpp_name = decl_full_name(other_comp_id); if(!is_capability_safe(other_capability)) { if(!unsafe_comps.contains(other_comp_id)) { diff --git a/runtime/index.bzl b/runtime/index.bzl index 238b050..648fe05 100644 --- a/runtime/index.bzl +++ b/runtime/index.bzl @@ -28,7 +28,6 @@ def ecsact_entt_runtime(name, srcs = [], deps = [], system_impls = [], tags = [] "@ecsact_lang_cpp//cpp_header_codegen", "@ecsact_lang_cpp//cpp_systems_header_codegen", "@ecsact_lang_cpp//systems_header_codegen", - "@ecsact_lang_cpp//cpp_meta_header_codegen", ], output_directory = "_%s__public_hdrs" % name, **kwargs @@ -42,7 +41,6 @@ def ecsact_entt_runtime(name, srcs = [], deps = [], system_impls = [], tags = [] strip_include_prefix = "_%s__public_hdrs" % name, deps = [ "@ecsact_lang_cpp//:execution_context", - "@ecsact_lang_cpp//:type_info", ], **kwargs ) diff --git a/test/MODULE.bazel b/test/MODULE.bazel index 5c51c23..0c98240 100644 --- a/test/MODULE.bazel +++ b/test/MODULE.bazel @@ -4,12 +4,12 @@ bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "googletest", version = "1.14.0") bazel_dep(name = "rules_ecsact", version = "0.5.2") -bazel_dep(name = "ecsact_lang_cpp", version = "0.4.1") -bazel_dep(name = "ecsact_runtime", version = "0.6.1") +bazel_dep(name = "ecsact_lang_cpp", version = "0.4.3") +bazel_dep(name = "ecsact_runtime", version = "0.6.5") bazel_dep(name = "boost.mp11", version = "1.83.0.bzl.1") bazel_dep(name = "boost.dll", version = "1.83.0.bzl.2") bazel_dep(name = "entt", version = "3.12.2") -bazel_dep(name = "ecsact_cli", version = "0.3.9") +bazel_dep(name = "ecsact_cli", version = "0.3.10") bazel_dep(name = "boost.process", version = "1.83.0.bzl.2") bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) @@ -20,6 +20,11 @@ git_override( remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git", ) +local_path_override( + module_name = "ecsact_lang_cpp", + path = "../../ecsact_lang_cpp", +) + # TODO: https://github.com/bazelbuild/bazel-central-registry/pull/1916 git_override( module_name = "libarchive", From b1319e06018012afe78ef35239ae16d7a48bf54f Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Tue, 11 Jun 2024 15:13:04 -0700 Subject: [PATCH 02/19] chore: wip --- ecsact/entt/assoc.hh | 16 ++++ ecsact/entt/detail/apply_pending.hh | 6 +- ecsact/entt/detail/hash.hh | 7 ++ ecsact/entt/detail/internal_lifecycle.hh | 53 +++++++++++++ rt_entt_codegen/core/print_sys_exec.cc | 26 ++++--- rt_entt_codegen/shared/parallel.cc | 16 ++-- rt_entt_codegen/shared/util.cc | 97 ++++++++++++++++++++++++ rt_entt_codegen/shared/util.hh | 67 +++++----------- 8 files changed, 217 insertions(+), 71 deletions(-) create mode 100644 ecsact/entt/assoc.hh create mode 100644 ecsact/entt/detail/internal_lifecycle.hh create mode 100644 rt_entt_codegen/shared/util.cc diff --git a/ecsact/entt/assoc.hh b/ecsact/entt/assoc.hh new file mode 100644 index 0000000..5e3f5ad --- /dev/null +++ b/ecsact/entt/assoc.hh @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace ecsact::entt { + +/** + * This struct is used to tag an entity as 'indexed'. The template parameter @tp + * C is only to make the code generation more clear which component is being + * indexed. Since the storage name is the identifying factor it should have no + * effect. + */ +template +struct indexed {}; + +} // namespace ecsact::entt diff --git a/ecsact/entt/detail/apply_pending.hh b/ecsact/entt/detail/apply_pending.hh index 80162ab..4304f36 100644 --- a/ecsact/entt/detail/apply_pending.hh +++ b/ecsact/entt/detail/apply_pending.hh @@ -10,15 +10,17 @@ template auto apply_pending_add(ecsact::entt::registry_t& registry) -> void { if constexpr(std::is_empty_v) { registry.view>().each([&](auto entity) { - registry.emplace(entity); + C& comp = registry.emplace(entity); + lifecycle_on_add(registry, entity, comp); }); } else { registry.view>().each( // [&](auto entity, const pending_add& comp) { - registry.emplace(entity, comp.value); + C& comp = registry.emplace(entity, comp.value); registry .emplace>(entity, comp.value, false); add_system_markers_if_needed(registry, entity); + lifecycle_on_add(registry, entity, comp); } ); } diff --git a/ecsact/entt/detail/hash.hh b/ecsact/entt/detail/hash.hh index c5b5392..0093a4b 100644 --- a/ecsact/entt/detail/hash.hh +++ b/ecsact/entt/detail/hash.hh @@ -1,5 +1,6 @@ #pragma once +#include "ecsact/entt/detail/bytes.hh" #include #include @@ -15,4 +16,10 @@ auto bytes_hash( // std::byte* data, int data_length ) -> std::uint64_t; + +template +auto hash_vals(Args&&... args) -> std::uint64_t { + auto bytes = bytes_copy(args...); + return bytes_hash(bytes.data(), bytes.size()); +} } // namespace ecsact::entt::detail diff --git a/ecsact/entt/detail/internal_lifecycle.hh b/ecsact/entt/detail/internal_lifecycle.hh new file mode 100644 index 0000000..151a2e3 --- /dev/null +++ b/ecsact/entt/detail/internal_lifecycle.hh @@ -0,0 +1,53 @@ +#pragma once + +#include +#include "entt/entt.hpp" +#include "ecsact/entt/entity.hh" +#include "ecsact/runtime/common.h" + +namespace ecsact::entt::detail { + +template +constexpr bool lifecycle_unimplemented_by_codegen = false; + +template< typename C> + requires(!std::is_empty_v) +auto lifecycle_on_add( // + ecsact::entt::registry_t&, + ecsact::entt::entity_id, + const C& +) -> void { + static_assert(lifecycle_unimplemented_by_codegen, R"( + ----------------------------------------------------------------------------- +| (!) CODEGEN ERROR - missing specialization | + ----------------------------------------------------------------------------- +)"); +} + +template + requires(std::is_empty_v) +auto lifecycle_on_add( // + ecsact::entt::registry_t&, + ecsact::entt::entity_id +) -> void { + static_assert(lifecycle_unimplemented_by_codegen, R"( + ----------------------------------------------------------------------------- +| (!) CODEGEN ERROR - missing specialization | + ----------------------------------------------------------------------------- +)"); +} + +template +auto lifecycle_on_update( + ecsact::entt::registry_t&, + ecsact::entt::entity_id, + const C& before, + const C& after +) -> void { + static_assert(lifecycle_unimplemented_by_codegen, R"( + ----------------------------------------------------------------------------- +| (!) CODEGEN ERROR - missing specialization | + ----------------------------------------------------------------------------- +)"); +} +} // namespace ecsact::entt::detail diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index c81f1a3..c342a69 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -34,6 +34,7 @@ concept system_or_action = using ecsact::cc_lang_support::cpp_identifier; using ecsact::cpp_codegen_plugin_util::block; +using ecsact::cpp_codegen_plugin_util::comma_delim; using ecsact::meta::decl_full_name; using ecsact::rt_entt_codegen::ecsact_entt_system_details; using ecsact::rt_entt_codegen::system_comps_with_caps; @@ -41,8 +42,11 @@ using ecsact::rt_entt_codegen::system_like_id_variant; using ecsact::rt_entt_codegen::core::provider::handle_exclusive_provide; using ecsact::rt_entt_codegen::core::provider::system_provider; using ecsact::rt_entt_codegen::system_util::is_trivial_system; +using ecsact::rt_entt_codegen::util::make_view; +using ecsact::rt_entt_codegen::util::make_view_options; using ecsact::rt_entt_codegen::util::method_printer; using namespace ecsact::rt_entt_codegen::core; +using namespace std::string_literals; using system_provider_t = std::vector>; @@ -377,25 +381,25 @@ static auto print_execute_systems( ) -> void { auto sys_caps = ecsact::meta::system_capabilities(sys_like_id); auto system_providers = setup_system_providers(sys_like_id); + auto sys_details = ecsact_entt_system_details::from_system_like(sys_like_id); + auto make_view_opts = make_view_options(sys_details); + make_view_opts.registry_var_name = names.registry_var_name; + make_view_opts.view_var_name = "view"; + make_view_opts.sys_like_id = sys_like_id; for(const auto& provider : system_providers) { provider->initialization(ctx, names); } - auto additional_view_components = std::vector{}; for(const auto& provider : system_providers) { - provider->before_make_view_or_group(ctx, names, additional_view_components); + provider->before_make_view_or_group( + ctx, + names, + make_view_opts.additional_components + ); } - auto sys_details = ecsact_entt_system_details::from_system_like(sys_like_id); - - ecsact::rt_entt_codegen::util::make_view( - ctx, - "view", - names.registry_var_name, - sys_details, - additional_view_components - ); + make_view(ctx, make_view_opts); ctx.write("using view_t = decltype(view);\n"); diff --git a/rt_entt_codegen/shared/parallel.cc b/rt_entt_codegen/shared/parallel.cc index 657199d..7bf7b8e 100644 --- a/rt_entt_codegen/shared/parallel.cc +++ b/rt_entt_codegen/shared/parallel.cc @@ -162,15 +162,13 @@ auto ecsact::rt_entt_codegen::parallel::can_entities_parallel( return false; } - auto other_fields = - ecsact::meta::system_association_fields(sys_like_id, comp_id); - - for(auto field_id : other_fields) { - auto other_capabilities = ecsact::meta::system_association_capabilities( - sys_like_id, - comp_id, - field_id - ); + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + + for(auto assoc_id : assoc_ids) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto other_capabilities = + ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); // NOTE(Kelwan): Association is currently not compatible with executing // entities in parallel. diff --git a/rt_entt_codegen/shared/util.cc b/rt_entt_codegen/shared/util.cc new file mode 100644 index 0000000..c571afd --- /dev/null +++ b/rt_entt_codegen/shared/util.cc @@ -0,0 +1,97 @@ +#include "util.hh" + +#include + +auto ecsact::rt_entt_codegen::util::make_view( // + ecsact::codegen_plugin_context& ctx, + make_view_options opts +) -> void { + using namespace std::string_literals; + using ecsact::rt_entt_codegen::util::comma_delim; + using ecsact::rt_entt_codegen::util::decl_cpp_ident; + using std::views::transform; + + ctx.write( + "auto ", + opts.view_var_name, + " = ", + opts.registry_var_name, + ".view<" + ); + + ctx.write(comma_delim( + opts.details.get_comps | transform(decl_cpp_ident) + )); + + for(auto comp_id : opts.details.writable_comps) { + auto comp_name = decl_cpp_ident(comp_id); + + opts.additional_components.push_back(std::format( + "ecsact::entt::detail::exec_beforechange_storage<{}>", + comp_name + )); + } + + if(!opts.additional_components.empty()) { + ctx.write(", "); + ctx.write(comma_delim(opts.additional_components)); + } + + ctx.write(">("); + + auto exclude_comps = opts.details.exclude_comps | + transform(decl_cpp_ident); + + opts.additional_exclude_components.insert( + opts.additional_exclude_components.end(), + exclude_comps.begin(), + exclude_comps.end() + ); + + if(!opts.additional_exclude_components.empty()) { + ctx.write( + "::entt::exclude<", + comma_delim(opts.additional_exclude_components), + ">" + ); + } + + ctx.write(");\n"); + + if(opts.sys_like_id && opts.sys_like_id->is_action()) { + auto act_id = opts.sys_like_id->as_action(); + auto indexed_fields = std::map< + ecsact_composite_id, + std::vector>>{}; + for(auto field_id : ecsact::meta::get_field_ids(act_id)) { + auto act_field_name = ecsact::meta::field_name(act_id, field_id); + auto field_type = ecsact::meta::get_field_type(act_id, field_id); + if(field_type.kind != ECSACT_TYPE_KIND_FIELD_INDEX) { + continue; + } + + indexed_fields[field_type.type.field_index.composite_id].push_back({ + field_type.type.field_index.field_id, + std::format("action.{}", act_field_name), + }); + } + + for(auto&& [compo_id, fields] : indexed_fields) { + auto compo_name = cpp_identifier(decl_full_name(compo_id)); + auto hash_fields_str = std::format( + "::ecsact::entt::detail::hash_vals(static_cast({}::id), {})", + compo_name, + comma_delim(std::views::transform( + fields, + [](auto& entry) -> std::string { return entry.second; } + )) + ); + ctx.write(std::format( + "view.storage({}.storage<::ecsact::entt::indexed<{}>>({}));\n", + names.registry_var_name, + compo_name, + hash_fields_str + )); + } + } +} diff --git a/rt_entt_codegen/shared/util.hh b/rt_entt_codegen/shared/util.hh index 02f22fe..0447042 100644 --- a/rt_entt_codegen/shared/util.hh +++ b/rt_entt_codegen/shared/util.hh @@ -11,6 +11,7 @@ #include "ecsact/runtime/meta.h" #include "ecsact/runtime/meta.hh" #include "ecsact_entt_details.hh" +#include "system_variant.hh" namespace ecsact::rt_entt_codegen::util { @@ -271,59 +272,27 @@ auto comma_delim(auto&& range) -> std::string { return result; } -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 additional_components = {}, - std::vector additional_exclude_components = {} -) -> void { - using namespace std::string_literals; - using ecsact::rt_entt_codegen::util::comma_delim; - using ecsact::rt_entt_codegen::util::decl_cpp_ident; - using std::views::transform; - - ctx.write("auto ", view_var_name, " = ", registry_var_name, ".view<"); +struct make_view_options { + std::string_view view_var_name; + std::string_view registry_var_name; + std::vector additional_components; + std::vector additional_exclude_components; + std::optional sys_like_id; - ctx.write(comma_delim( - details.get_comps | transform(decl_cpp_ident) - )); + const ecsact_entt_system_details& details; - for(auto comp_id : details.writable_comps) { - auto comp_name = decl_cpp_ident(comp_id); - - additional_components.push_back(std::format( - "ecsact::entt::detail::exec_beforechange_storage<{}>", - comp_name - )); + inline make_view_options(ecsact_entt_system_details& details) + : details(details) { } - if(!additional_components.empty()) { - ctx.write(", "); - ctx.write(comma_delim(additional_components)); - } - - ctx.write(">("); - - 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(additional_exclude_components), - ">" - ); - } + inline make_view_options(make_view_options&&) = default; + inline make_view_options(const make_view_options&) = default; + inline ~make_view_options() = default; +}; - ctx.write(");\n"); -} +auto make_view( // + ecsact::codegen_plugin_context& ctx, + make_view_options opts +) -> void; } // namespace ecsact::rt_entt_codegen::util From 42ff13f612b873ab0691ac7748813a1371e41734 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Wed, 19 Jun 2024 18:07:03 -0700 Subject: [PATCH 03/19] chore: wip --- MODULE.bazel | 10 +- .../association/association.cc | 335 +++++++++--------- .../association/association.hh | 61 ++-- .../core/system_provider/lazy/lazy.cc | 12 +- rt_entt_codegen/shared/BUILD.bazel | 2 + rt_entt_codegen/shared/ecsact_entt_details.cc | 7 + rt_entt_codegen/shared/ecsact_entt_details.hh | 5 + rt_entt_codegen/shared/parallel.cc | 42 +-- rt_entt_codegen/shared/parallel.hh | 2 +- rt_entt_codegen/shared/util.cc | 12 +- rt_entt_codegen/shared/util.hh | 21 +- test/MODULE.bazel | 14 +- test/runtime_test.cc | 20 +- 13 files changed, 291 insertions(+), 252 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index c07e3c3..78955b8 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -12,9 +12,8 @@ bazel_dep(name = "ecsact_lang_cpp", version = "0.4.3") bazel_dep(name = "boost.mp11", version = "1.83.0.bzl.1") bazel_dep(name = "entt", version = "3.12.2") bazel_dep(name = "ecsact_codegen", version = "0.2.0") -bazel_dep(name = "ecsact_cli", version = "0.3.10") +bazel_dep(name = "ecsact_cli", version = "0.3.11") bazel_dep(name = "xxhash", version = "0.8.2") -bazel_dep(name = "googletest", version = "1.14.0.bcr.1") local_path_override( module_name = "ecsact_lang_cpp", @@ -29,13 +28,6 @@ git_override( remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git", ) -# TODO: https://github.com/bazelbuild/bazel-central-registry/pull/1916 -git_override( - module_name = "libarchive", - commit = "7c331f92acea5243c195cdc6fb46ecfa11ce1ce2", - remote = "https://github.com/zaucy/libarchive.git", -) - llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm", dev_dependency = True) llvm.toolchain(llvm_version = "17.0.6") use_repo(llvm, "llvm_toolchain") diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index 2a99ff7..c187f6e 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -8,14 +8,33 @@ #include "ecsact/runtime/meta.hh" #include "ecsact/cpp_codegen_plugin_util.hh" +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::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::get_unique_view_name; +using ecsact::rt_entt_codegen::util::method_printer; + using capability_t = std::unordered_map; using namespace ecsact::rt_entt_codegen::core; +auto provider::association::initialization( + codegen_plugin_context& ctx, + const common_vars& names +) -> void { + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + for(auto assoc_id : assoc_ids) { + assoc_view_names.insert({assoc_id, get_unique_view_name()}); + } +} + auto provider::association::context_function_header( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::core::common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void { ctx.write( "std::unordered_map void { + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + for(auto assoc_id : assoc_ids) { + auto assoc_caps = + ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); + auto assoc_system_details = + ecsact_entt_system_details::from_capabilities(assoc_caps); + auto make_view_opts = util::make_view_options(assoc_system_details); + make_view_opts.view_var_name = assoc_view_names.at(assoc_id); + make_view_opts.registry_var_name = names.registry_var_name; + + util::make_view(ctx, make_view_opts); + } } auto provider::association::context_function_other( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::core::common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> handle_exclusive_provide { context_other_impl(ctx, sys_like_id, system_details); return HANDLED; } +auto provider::association::entity_iteration( + codegen_plugin_context& ctx, + const common_vars& names, + std::function iter_func +) -> handle_exclusive_provide { + block(ctx, "for(auto entity : view)", [&] { + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + auto assoc_caps = + ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); + auto assoc_system_details = + ecsact_entt_system_details::from_capabilities(assoc_caps); + auto make_view_opts = util::make_view_options(assoc_system_details); + make_view_opts.view_var_name = assoc_view_names.at(assoc_id); + make_view_opts.registry_var_name = names.registry_var_name; + + util::make_view(ctx, make_view_opts); + } + + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto assoc_field_ids = + ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); + auto assoc_comp_cpp_ident = cpp_identifier(decl_full_name(assoc_comp_id)); + + ctx.write(std::format( + "{0}.storage<{1}>(::ecsact::entt::detail::hash_vals({1}::id, {2});\n", + assoc_view_names.at(assoc_id), + assoc_comp_cpp_ident, + util::comma_delim( + assoc_field_ids | + std::views::transform([&](auto field_id) -> std::string { + return std::format( + "view.get<{}>(entity).{}", + assoc_comp_cpp_ident, + ecsact::meta::field_name(assoc_comp_id, field_id) + ); + }) + ) + )); + } + + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + ctx.write(std::format( + "auto {0}_itr = {0}.begin();\n", + assoc_view_names.at(assoc_id) + )); + } + + block(ctx, "for(;;)", [&] { + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + ctx.write(std::format( + "if({0}_itr == {0}.end()) break;\n", + assoc_view_names.at(assoc_id) + )); + } + + iter_func(); + + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + ctx.write(std::format("{}_itr++;\n", assoc_view_names.at(assoc_id))); + } + }); + }); + + return HANDLED; +} + auto provider::association::pre_entity_iteration( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::core::common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void { print_other_contexts(ctx, names); } auto provider::association::pre_exec_system_impl( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::core::common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void { - using ecsact::cc_lang_support::cpp_identifier; - using ecsact::meta::decl_full_name; - using ecsact::rt_entt_codegen::system_util::create_context_var_name; - - int comp_iter = 0; - - for(auto [ids, view_name] : other_view_names) { - if(!components_with_entity_fields.contains(ids.component_like_id)) { - components_with_entity_fields[ids.component_like_id] = - "assoc_comp_" + std::to_string(comp_iter++); - } - } - - for(auto&& [comp_like_id, comp_var] : components_with_entity_fields) { - auto comp_name = cpp_identifier(decl_full_name(comp_like_id)); - ctx.write("auto ", comp_var, " = view.get<", comp_name, ">(entity);\n"); - } - - ctx.write("auto found_assoc_entities = 0;\n"); - - for(auto [ids, view_name] : other_view_names) { - auto field_name = ecsact_meta_field_name( - ecsact_id_cast(ids.component_like_id), - ids.field_id - ); - - auto entity_field_access = - components_with_entity_fields.at(ids.component_like_id) + "." + - field_name; - - auto view_itr_name = view_name + "_itr"; - ctx.write( - "auto ", - view_itr_name, - " = ", - view_name, - ".find(ecsact::entt::entity_id{", - entity_field_access, - "});\n" - ); - - ctx.write( - "if(", - view_itr_name, - " == ", - view_name, - ".end()) { continue; }\n" - ); - - ctx.write("found_assoc_entities += 1;\n"); - - auto context_name = create_context_var_name(ids.component_like_id); - ctx.write(context_name, ".entity = ", entity_field_access, ";\n"); - - ctx.write( - "context.other_contexts.insert(context.other_contexts.end(), " - "std::pair(", - context_name, - ".entity, &", - context_name, - "));\n" - ); - } } auto provider::association::system_impl( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::core::common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> handle_exclusive_provide { - using ecsact::cpp_codegen_plugin_util::block; - - // we need to check if we found any invalid associations - block( - ctx, - "if(found_assoc_entities == " + std::to_string(other_view_names.size()) + - ")", - [&] { ctx.write("system_impl(&context);\n"); } - ); + ctx.write("system_impl(&context);\n"); return HANDLED; } auto provider::association::print_other_contexts( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::core::common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void { - 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; - 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; - - for(auto& assoc_detail : system_details.association_details) { - auto struct_name = create_context_struct_name(assoc_detail.component_id); - auto context_name = create_context_var_name(assoc_detail.component_id); - + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + for(auto assoc_id : assoc_ids) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto struct_name = create_context_struct_name(assoc_comp_id); + auto context_name = create_context_var_name(assoc_comp_id); auto struct_header = struct_name + " : ecsact_system_execution_context "; - - auto view_type_name = get_unique_view_name(); - other_view_names.insert( - other_view_names.end(), - std::pair( - other_key{ - .component_like_id = assoc_detail.component_id, - .field_id = assoc_detail.field_id // - }, - view_type_name - ) - ); - - auto other_details = - ecsact_entt_system_details::from_capabilities(assoc_detail.capabilities); - - ecsact::rt_entt_codegen::util::make_view( - ctx, - view_type_name, - "registry", - other_details - ); + auto assoc_caps = + ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); + auto assoc_system_details = + ecsact_entt_system_details::from_capabilities(assoc_caps); ctx.write(std::format( - "using {}_t = decltype({});\n", - view_type_name, - view_type_name + "using {0}_t = decltype({0});\n", + assoc_view_names.at(assoc_id) )); block(ctx, "struct " + struct_header, [&] { @@ -185,37 +184,47 @@ auto provider::association::print_other_contexts( using ecsact::rt_entt_codegen::util::decl_cpp_ident; using std::views::transform; - ctx.write(std::format("{}_t* view;\n", view_type_name)); + ctx.write(std::format("{}_t* view;\n", assoc_view_names.at(assoc_id))); ctx.write("\n"); print_other_ctx_action(ctx); - print_other_ctx_add(ctx, assoc_detail.capabilities, other_details); + print_other_ctx_add( + ctx, + std::unordered_map{assoc_caps.begin(), assoc_caps.end()}, + assoc_system_details + ); print_other_ctx_remove( ctx, - assoc_detail.capabilities, - other_details, - view_type_name + std::unordered_map{assoc_caps.begin(), assoc_caps.end()}, + assoc_system_details, + assoc_view_names.at(assoc_id) + ); + print_other_ctx_get( + ctx, + assoc_system_details, + assoc_view_names.at(assoc_id) + ); + print_other_ctx_update( + ctx, + assoc_system_details, + assoc_view_names.at(assoc_id) ); - print_other_ctx_get(ctx, other_details, view_type_name); - print_other_ctx_update(ctx, other_details, view_type_name); - print_other_ctx_has(ctx, other_details); - print_other_ctx_generate(ctx, other_details); + print_other_ctx_has(ctx, assoc_system_details); + print_other_ctx_generate(ctx, assoc_system_details); print_other_ctx_parent(ctx, sys_like_id); - print_other_ctx_other(ctx, other_details); + print_other_ctx_other(ctx, assoc_system_details); }); ctx.write(";\n\n"); ctx.write(struct_name, " ", context_name, ";\n\n"); - ctx.write(context_name, ".view = &", view_type_name, ";\n"); + ctx.write(context_name, ".view = &", assoc_view_names.at(assoc_id), ";\n"); ctx.write(context_name, ".parent_ctx = nullptr;\n\n"); ctx.write(context_name, ".registry = &", names.registry_var_name, ";\n"); } } -using ecsact::rt_entt_codegen::util::method_printer; - -auto provider::association::print_other_ctx_action( - ecsact::codegen_plugin_context& ctx +auto provider::association::print_other_ctx_action( // + codegen_plugin_context& ctx ) -> void { auto printer = // method_printer{ctx, "action"} @@ -226,9 +235,9 @@ auto provider::association::print_other_ctx_action( } auto provider::association::print_other_ctx_add( - ecsact::codegen_plugin_context& ctx, - const capability_t& other_caps, - const ecsact::rt_entt_codegen::ecsact_entt_system_details& details + codegen_plugin_context& ctx, + const capability_t& other_caps, + const ecsact_entt_system_details& details ) -> void { auto printer = // method_printer{ctx, "add"} @@ -240,10 +249,10 @@ auto provider::association::print_other_ctx_add( } auto provider::association::print_other_ctx_remove( - ecsact::codegen_plugin_context& ctx, - const capability_t& other_caps, - const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, - const std::string& view_type_name + codegen_plugin_context& ctx, + const capability_t& other_caps, + const ecsact_entt_system_details& details, + const std::string& view_type_name ) -> void { auto printer = // method_printer{ctx, "remove"} @@ -254,9 +263,9 @@ auto provider::association::print_other_ctx_remove( } auto provider::association::print_other_ctx_get( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, - const std::string& view_type_name + codegen_plugin_context& ctx, + const ecsact_entt_system_details& details, + const std::string& view_type_name ) -> void { auto printer = // method_printer{ctx, "get"} @@ -268,9 +277,9 @@ auto provider::association::print_other_ctx_get( } auto provider::association::print_other_ctx_update( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::ecsact_entt_system_details& details, - const std::string& view_type_name + codegen_plugin_context& ctx, + const ecsact_entt_system_details& details, + const std::string& view_type_name ) -> void { auto printer = // method_printer{ctx, "update"} @@ -282,8 +291,8 @@ auto provider::association::print_other_ctx_update( } auto provider::association::print_other_ctx_has( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::ecsact_entt_system_details& details + codegen_plugin_context& ctx, + const ecsact_entt_system_details& details ) -> void { auto printer = // method_printer{ctx, "has"} @@ -294,8 +303,8 @@ auto provider::association::print_other_ctx_has( } auto provider::association::print_other_ctx_generate( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::ecsact_entt_system_details& details + codegen_plugin_context& ctx, + const ecsact_entt_system_details& details ) -> void { auto printer = // method_printer{ctx, "generate"} @@ -308,8 +317,8 @@ auto provider::association::print_other_ctx_generate( } auto provider::association::print_other_ctx_parent( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::system_like_id_variant& sys_like_id + codegen_plugin_context& ctx, + const system_like_id_variant& sys_like_id ) -> void { auto printer = // method_printer{ctx, "parent"} // @@ -319,8 +328,8 @@ auto provider::association::print_other_ctx_parent( } auto provider::association::print_other_ctx_other( - ecsact::codegen_plugin_context& ctx, - const ecsact::rt_entt_codegen::ecsact_entt_system_details& details + codegen_plugin_context& ctx, + const ecsact_entt_system_details& details ) -> void { auto printer = // method_printer{ctx, "other"} diff --git a/rt_entt_codegen/core/system_provider/association/association.hh b/rt_entt_codegen/core/system_provider/association/association.hh index 834098e..674a2d1 100644 --- a/rt_entt_codegen/core/system_provider/association/association.hh +++ b/rt_entt_codegen/core/system_provider/association/association.hh @@ -11,89 +11,98 @@ class association final : public system_provider { public: using system_provider::system_provider; + auto initialization( // + codegen_plugin_context& ctx, + const common_vars& names + ) -> void final; + + auto entity_iteration( + codegen_plugin_context& ctx, + const common_vars& names, + std::function iter_func + ) -> handle_exclusive_provide final; + auto after_make_view_or_group( - ecsact::codegen_plugin_context& ctx, - const common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void final; auto context_function_header( - ecsact::codegen_plugin_context& ctx, - const common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void final; auto context_function_other( - ecsact::codegen_plugin_context& ctx, - const common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> handle_exclusive_provide final; auto pre_entity_iteration( - ecsact::codegen_plugin_context& ctx, - const common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void final; auto pre_exec_system_impl( - ecsact::codegen_plugin_context& ctx, - const common_vars& names + codegen_plugin_context& ctx, + const common_vars& names ) -> void final; - auto system_impl( - ecsact::codegen_plugin_context& ctx, - const common_vars& names + auto system_impl( // + codegen_plugin_context& ctx, + const common_vars& names ) -> handle_exclusive_provide final; private: - std::map other_view_names; - - std::map components_with_entity_fields; + std::map assoc_view_names; auto print_other_contexts( ecsact::codegen_plugin_context& ctx, const common_vars& names ) -> void; - auto print_other_ctx_action(ecsact::codegen_plugin_context& ctx) -> void; + auto print_other_ctx_action(codegen_plugin_context& ctx) -> void; auto print_other_ctx_add( - ecsact::codegen_plugin_context& ctx, + codegen_plugin_context& ctx, const capability_t& other_caps, const ecsact_entt_system_details& details ) -> void; auto print_other_ctx_remove( - ecsact::codegen_plugin_context& ctx, + codegen_plugin_context& ctx, const capability_t& other_caps, const ecsact_entt_system_details& details, const std::string& view_type_name ) -> void; auto print_other_ctx_get( - ecsact::codegen_plugin_context& ctx, + codegen_plugin_context& ctx, const ecsact_entt_system_details& details, const std::string& view_type_name ) -> void; auto print_other_ctx_update( - ecsact::codegen_plugin_context& ctx, + codegen_plugin_context& ctx, const ecsact_entt_system_details& details, const std::string& view_type_name ) -> void; auto print_other_ctx_has( - ecsact::codegen_plugin_context& ctx, + codegen_plugin_context& ctx, const ecsact_entt_system_details& details ) -> void; auto print_other_ctx_generate( - ecsact::codegen_plugin_context& ctx, + codegen_plugin_context& ctx, const ecsact_entt_system_details& details ) -> void; auto print_other_ctx_parent( - ecsact::codegen_plugin_context& ctx, - const system_like_id_variant& sys_like_id + codegen_plugin_context& ctx, + const system_like_id_variant& sys_like_id ) -> void; auto print_other_ctx_other( - ecsact::codegen_plugin_context& ctx, + codegen_plugin_context& ctx, const ecsact_entt_system_details& details ) -> void; }; diff --git a/rt_entt_codegen/core/system_provider/lazy/lazy.cc b/rt_entt_codegen/core/system_provider/lazy/lazy.cc index e5e9c89..e0b6547 100644 --- a/rt_entt_codegen/core/system_provider/lazy/lazy.cc +++ b/rt_entt_codegen/core/system_provider/lazy/lazy.cc @@ -117,12 +117,12 @@ auto provider::lazy::post_iteration( ">([](const auto& a, const auto& b) { return a.hash < b.hash; });\n" ); - ecsact::rt_entt_codegen::util::make_view( - ctx, - "view_no_pending_lazy_", - names.registry_var_name, - system_details - ); + auto make_view_opts = util::make_view_options(system_details); + make_view_opts.view_var_name = "view_no_pending_lazy_"; + make_view_opts.registry_var_name = names.registry_var_name; + make_view_opts.sys_like_id = sys_like_id; + + ecsact::rt_entt_codegen::util::make_view(ctx, make_view_opts); ctx.write("auto view_no_pending_lazy_count_ = 0;\n"); diff --git a/rt_entt_codegen/shared/BUILD.bazel b/rt_entt_codegen/shared/BUILD.bazel index 0147e6b..eff6170 100644 --- a/rt_entt_codegen/shared/BUILD.bazel +++ b/rt_entt_codegen/shared/BUILD.bazel @@ -32,10 +32,12 @@ cc_library( cc_library( name = "util", hdrs = ["util.hh"], + srcs = ["util.cc"], copts = copts, defines = ["ECSACT_META_API_LOAD_AT_RUNTIME"], deps = [ ":comps_with_caps", + ":system_variant", "@ecsact_codegen//:plugin", "@ecsact_lang_cpp//:support", "@ecsact_runtime//:common", diff --git a/rt_entt_codegen/shared/ecsact_entt_details.cc b/rt_entt_codegen/shared/ecsact_entt_details.cc index ee37ede..c18c7ae 100644 --- a/rt_entt_codegen/shared/ecsact_entt_details.cc +++ b/rt_entt_codegen/shared/ecsact_entt_details.cc @@ -180,6 +180,13 @@ auto ecsact_entt_system_details::from_capabilities( // return details; } +auto ecsact_entt_system_details::from_capabilities( + std::vector> + caps +) -> ecsact_entt_system_details { + return from_capabilities(std::unordered_map{caps.begin(), caps.end()}); +} + auto ecsact_entt_details::from_package( // ecsact_package_id pkg_id ) -> ecsact_entt_details { diff --git a/rt_entt_codegen/shared/ecsact_entt_details.hh b/rt_entt_codegen/shared/ecsact_entt_details.hh index a140d21..7990946 100644 --- a/rt_entt_codegen/shared/ecsact_entt_details.hh +++ b/rt_entt_codegen/shared/ecsact_entt_details.hh @@ -60,6 +60,11 @@ struct ecsact_entt_system_details { std::unordered_map caps ) -> ecsact_entt_system_details; + static auto from_capabilities( + std::vector> + caps + ) -> ecsact_entt_system_details; + private: static auto fill_system_details( ecsact_entt_system_details& in_details, diff --git a/rt_entt_codegen/shared/parallel.cc b/rt_entt_codegen/shared/parallel.cc index 7bf7b8e..8fd9058 100644 --- a/rt_entt_codegen/shared/parallel.cc +++ b/rt_entt_codegen/shared/parallel.cc @@ -7,7 +7,6 @@ #include "ecsact/lang-support/lang-cc.hh" #include "rt_entt_codegen/shared/system_variant.hh" -#include "system_variant.hh" #include "ecsact/runtime/meta.hh" using ecsact::rt_entt_codegen::system_like_id_variant; @@ -251,6 +250,7 @@ static auto loop_iterator( loop_iterator(system_list, iterator, parallel_system_cluster); return; } else { + // TODO: check if capability safe child_unsafe_comps.insert(child_comp_id); } } @@ -278,27 +278,27 @@ static auto loop_iterator( return; } } + } - auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); - - for(auto assoc_id : assoc_ids) { - auto assoc_comp_id = - ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); - auto assoc_field_ids = - ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); - auto assoc_capabilities = - ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); - - for(const auto [other_comp_id, other_capability] : assoc_capabilities) { - auto cpp_name = decl_full_name(other_comp_id); - if(!is_capability_safe(other_capability)) { - if(!unsafe_comps.contains(other_comp_id)) { - unsafe_comps.insert(other_comp_id); - } else { - parallel_system_cluster.push_back(parallel_system_list); - loop_iterator(system_list, iterator, parallel_system_cluster); - return; - } + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + for(auto assoc_id : assoc_ids) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto assoc_field_ids = + ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); + auto assoc_capabilities = + ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); + + for(const auto [other_comp_id, other_capability] : assoc_capabilities) { + auto cpp_name = decl_full_name(other_comp_id); + if(!is_capability_safe(other_capability)) { + if(!unsafe_comps.contains(other_comp_id)) { + unsafe_comps.insert(other_comp_id); + } else { + assert(!parallel_system_list.empty()); + parallel_system_cluster.push_back(parallel_system_list); + loop_iterator(system_list, iterator, parallel_system_cluster); + return; } } } diff --git a/rt_entt_codegen/shared/parallel.hh b/rt_entt_codegen/shared/parallel.hh index 7e163df..3e0ff1d 100644 --- a/rt_entt_codegen/shared/parallel.hh +++ b/rt_entt_codegen/shared/parallel.hh @@ -2,7 +2,7 @@ #include "ecsact/codegen/plugin.hh" #include "rt_entt_codegen/shared/ecsact_entt_details.hh" -#include "system_variant.hh" +#include "rt_entt_codegen/shared/system_variant.hh" namespace ecsact::rt_entt_codegen::parallel { auto get_parallel_execution_cluster( diff --git a/rt_entt_codegen/shared/util.cc b/rt_entt_codegen/shared/util.cc index c571afd..35b2188 100644 --- a/rt_entt_codegen/shared/util.cc +++ b/rt_entt_codegen/shared/util.cc @@ -2,15 +2,15 @@ #include +using namespace std::string_literals; +using ecsact::cc_lang_support::cpp_identifier; +using ecsact::meta::decl_full_name; +using std::views::transform; + auto ecsact::rt_entt_codegen::util::make_view( // ecsact::codegen_plugin_context& ctx, make_view_options opts ) -> void { - using namespace std::string_literals; - using ecsact::rt_entt_codegen::util::comma_delim; - using ecsact::rt_entt_codegen::util::decl_cpp_ident; - using std::views::transform; - ctx.write( "auto ", opts.view_var_name, @@ -88,7 +88,7 @@ auto ecsact::rt_entt_codegen::util::make_view( // ); ctx.write(std::format( "view.storage({}.storage<::ecsact::entt::indexed<{}>>({}));\n", - names.registry_var_name, + opts.registry_var_name, compo_name, hash_fields_str )); diff --git a/rt_entt_codegen/shared/util.hh b/rt_entt_codegen/shared/util.hh index 0447042..45c7ad2 100644 --- a/rt_entt_codegen/shared/util.hh +++ b/rt_entt_codegen/shared/util.hh @@ -11,7 +11,7 @@ #include "ecsact/runtime/meta.h" #include "ecsact/runtime/meta.hh" #include "ecsact_entt_details.hh" -#include "system_variant.hh" +#include "rt_entt_codegen/shared/system_variant.hh" namespace ecsact::rt_entt_codegen::util { @@ -281,7 +281,7 @@ struct make_view_options { const ecsact_entt_system_details& details; - inline make_view_options(ecsact_entt_system_details& details) + inline make_view_options(const ecsact_entt_system_details& details) : details(details) { } @@ -295,4 +295,21 @@ auto make_view( // make_view_options opts ) -> void; +[[deprecated("use make_view() overload that uses make_view_options instead")]] +inline 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 additional_components = {}, + std::vector additional_exclude_components = {} +) -> void { + auto opts = make_view_options{details}; + opts.registry_var_name = registry_var_name; + opts.view_var_name = view_var_name; + opts.additional_components = additional_components; + opts.additional_exclude_components = additional_exclude_components; + return make_view(ctx, opts); +} + } // namespace ecsact::rt_entt_codegen::util diff --git a/test/MODULE.bazel b/test/MODULE.bazel index 0c98240..87345cf 100644 --- a/test/MODULE.bazel +++ b/test/MODULE.bazel @@ -9,7 +9,7 @@ bazel_dep(name = "ecsact_runtime", version = "0.6.5") bazel_dep(name = "boost.mp11", version = "1.83.0.bzl.1") bazel_dep(name = "boost.dll", version = "1.83.0.bzl.2") bazel_dep(name = "entt", version = "3.12.2") -bazel_dep(name = "ecsact_cli", version = "0.3.10") +bazel_dep(name = "ecsact_cli", version = "0.3.11") bazel_dep(name = "boost.process", version = "1.83.0.bzl.2") bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) @@ -21,15 +21,13 @@ git_override( ) local_path_override( - module_name = "ecsact_lang_cpp", - path = "../../ecsact_lang_cpp", + module_name = "ecsact_runtime", + path = "../../ecsact_runtime", ) -# TODO: https://github.com/bazelbuild/bazel-central-registry/pull/1916 -git_override( - module_name = "libarchive", - commit = "7c331f92acea5243c195cdc6fb46ecfa11ce1ce2", - remote = "https://github.com/zaucy/libarchive.git", +local_path_override( + module_name = "ecsact_lang_cpp", + path = "../../ecsact_lang_cpp", ) bazel_dep(name = "ecsact_rt_entt") diff --git a/test/runtime_test.cc b/test/runtime_test.cc index 13ee741..6d013c5 100644 --- a/test/runtime_test.cc +++ b/test/runtime_test.cc @@ -35,7 +35,7 @@ void runtime_test::SimpleSystem::impl(context& ctx) { void runtime_test::OtherEntitySystem::impl(context& ctx) { auto comp = ctx.get(); - auto other = ctx._ctx.other(comp.target); + auto other = ctx.other<0>(); auto other_comp = other.get(); comp.num += -other_comp.a; @@ -93,7 +93,7 @@ void runtime_test::AssocTestAction::impl(context& ctx) { void runtime_test::AttackDamage::impl(context& ctx) { // auto attacking = ctx.get(); - // auto target_ctx = ctx._ctx.other(attacking.target); + // auto target_ctx = ctx._ctx.other(); // auto target_health = target_ctx.get(); // target_health.value -= 1.f; // target_ctx.update(target_health); @@ -101,7 +101,7 @@ void runtime_test::AttackDamage::impl(context& ctx) { void runtime_test::AttackDamageWeakened::impl(context& ctx) { // auto attacking = ctx.get(); - // auto target_ctx = ctx._ctx.other(attacking.target); + // auto target_ctx = ctx._ctx.other(); // auto target_health = target_ctx.get(); // auto target_weakened = target_ctx.get(); // target_health.value -= 1.f * target_weakened.value; @@ -157,8 +157,8 @@ void runtime_test::AddAssocTest::impl(context& ctx) { auto other_entity = ctx.get(); // Get Target other context from OtherEntityComponent - auto target_ctx = ctx._ctx.other(other_entity.target); - assert(target_ctx._ctx != nullptr); + auto target_ctx = ctx.other(); + assert(target_ctx._ctx._ctx != nullptr); target_ctx.add(AddAssocTestComponent{.num = 10}); } @@ -169,7 +169,7 @@ void runtime_test::RemoveAssocTest::impl(context& ctx) { auto other_entity = ctx.get(); // Get Target other context from OtherEntityComponent - auto target_ctx = ctx._ctx.other(other_entity.target); + auto target_ctx = ctx.other(); target_ctx.remove(); } @@ -694,9 +694,9 @@ TEST(Core, AssociationEntityCorrectness) { ecsact_id_cast(AttackDamageWeakened::id), [](ecsact_system_execution_context* cctx) { ++attack_damage_weakened_exec_count; - ecsact::execution_context ctx{cctx}; + AttackDamageWeakened::context ctx{cctx}; ASSERT_TRUE(attacker_entities.contains(ctx.entity())); - auto target_ctx = ctx.other(ctx.get().target); + auto target_ctx = ctx.other(); ASSERT_TRUE(weakened_target_entities.contains(target_ctx.entity())); } ); @@ -705,11 +705,11 @@ TEST(Core, AssociationEntityCorrectness) { ecsact_id_cast(AttackDamage::id), [](ecsact_system_execution_context* cctx) { ++attack_damage_exec_count; - ecsact::execution_context ctx{cctx}; + AttackDamage::context ctx{cctx}; ASSERT_TRUE(attacker_entities.contains(ctx.entity())); // Sanity check - no exception - ctx.other(ctx.get().target); + ctx.other(); } ); From 27b375e48c8ecebdd37fbf49e12c67e2a3c963ea Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 20 Jun 2024 08:49:46 -0700 Subject: [PATCH 04/19] feat: attempting to create storage with runtime value --- ecsact/entt/detail/bytes.hh | 4 ++-- .../core/system_provider/association/association.cc | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ecsact/entt/detail/bytes.hh b/ecsact/entt/detail/bytes.hh index 7edc49d..e3d2a60 100644 --- a/ecsact/entt/detail/bytes.hh +++ b/ecsact/entt/detail/bytes.hh @@ -9,7 +9,7 @@ namespace ecsact::entt::detail { template - requires(std::integral || std::floating_point) + requires(std::integral || std::floating_point || std::is_enum_v) constexpr auto bytes_sizeof() -> int { using value_type = std::remove_cvref_t; @@ -43,7 +43,7 @@ template using unsigned_bit_size_equivalent_t = unsigned_bit_size_equivalent::type; template - requires(std::integral || std::floating_point) + requires(std::integral || std::floating_point || std::is_enum_v) auto bytes_copy_into( // T v, auto& out_bytes, diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index c187f6e..69ce242 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -95,7 +95,10 @@ auto provider::association::entity_iteration( auto assoc_comp_cpp_ident = cpp_identifier(decl_full_name(assoc_comp_id)); ctx.write(std::format( - "{0}.storage<{1}>(::ecsact::entt::detail::hash_vals({1}::id, {2});\n", + "{0}.storage({3}.storage<{1}>(static_cast<::entt::id_type>(::ecsact::" + "entt::detail::" + "hash_vals({1}::" + "id, {2}))));\n", assoc_view_names.at(assoc_id), assoc_comp_cpp_ident, util::comma_delim( @@ -107,7 +110,8 @@ auto provider::association::entity_iteration( ecsact::meta::field_name(assoc_comp_id, field_id) ); }) - ) + ), + names.registry_var_name )); } From 75627d8fe41456608d58770602132486301ef0e4 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 20 Jun 2024 12:08:26 -0700 Subject: [PATCH 05/19] chore: wip --- ecsact/entt/detail/apply_pending.hh | 6 +- ecsact/entt/detail/internal_lifecycle.hh | 53 -------------- .../association/association.cc | 72 +++++++++++++------ .../association/association.hh | 9 ++- runtime/hash.cc | 18 +++++ 5 files changed, 81 insertions(+), 77 deletions(-) delete mode 100644 ecsact/entt/detail/internal_lifecycle.hh diff --git a/ecsact/entt/detail/apply_pending.hh b/ecsact/entt/detail/apply_pending.hh index 4304f36..2c2ec92 100644 --- a/ecsact/entt/detail/apply_pending.hh +++ b/ecsact/entt/detail/apply_pending.hh @@ -11,16 +11,16 @@ auto apply_pending_add(ecsact::entt::registry_t& registry) -> void { if constexpr(std::is_empty_v) { registry.view>().each([&](auto entity) { C& comp = registry.emplace(entity); - lifecycle_on_add(registry, entity, comp); + // lifecycle_on_add(registry, entity, comp); }); } else { registry.view>().each( // [&](auto entity, const pending_add& comp) { - C& comp = registry.emplace(entity, comp.value); + registry.emplace(entity, comp.value); registry .emplace>(entity, comp.value, false); add_system_markers_if_needed(registry, entity); - lifecycle_on_add(registry, entity, comp); + // lifecycle_on_add(registry, entity, comp.value); } ); } diff --git a/ecsact/entt/detail/internal_lifecycle.hh b/ecsact/entt/detail/internal_lifecycle.hh deleted file mode 100644 index 151a2e3..0000000 --- a/ecsact/entt/detail/internal_lifecycle.hh +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include "entt/entt.hpp" -#include "ecsact/entt/entity.hh" -#include "ecsact/runtime/common.h" - -namespace ecsact::entt::detail { - -template -constexpr bool lifecycle_unimplemented_by_codegen = false; - -template< typename C> - requires(!std::is_empty_v) -auto lifecycle_on_add( // - ecsact::entt::registry_t&, - ecsact::entt::entity_id, - const C& -) -> void { - static_assert(lifecycle_unimplemented_by_codegen, R"( - ----------------------------------------------------------------------------- -| (!) CODEGEN ERROR - missing specialization | - ----------------------------------------------------------------------------- -)"); -} - -template - requires(std::is_empty_v) -auto lifecycle_on_add( // - ecsact::entt::registry_t&, - ecsact::entt::entity_id -) -> void { - static_assert(lifecycle_unimplemented_by_codegen, R"( - ----------------------------------------------------------------------------- -| (!) CODEGEN ERROR - missing specialization | - ----------------------------------------------------------------------------- -)"); -} - -template -auto lifecycle_on_update( - ecsact::entt::registry_t&, - ecsact::entt::entity_id, - const C& before, - const C& after -) -> void { - static_assert(lifecycle_unimplemented_by_codegen, R"( - ----------------------------------------------------------------------------- -| (!) CODEGEN ERROR - missing specialization | - ----------------------------------------------------------------------------- -)"); -} -} // namespace ecsact::entt::detail diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index 69ce242..eab28bf 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -28,7 +28,29 @@ auto provider::association::initialization( ) -> void { auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); for(auto assoc_id : assoc_ids) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto assoc_field_ids = + ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); assoc_view_names.insert({assoc_id, get_unique_view_name()}); + + for(auto field_id : assoc_field_ids) { + auto field_type = ecsact::meta::get_field_type(assoc_comp_id, field_id); + if(field_type.kind == ECSACT_TYPE_KIND_BUILTIN && + field_type.type.builtin == ECSACT_ENTITY_TYPE) { + auto compo_id = ecsact_id_cast(assoc_comp_id); + assoc_fields[compo_id].push_back(field_id); + assoc_composites[assoc_id].insert(compo_id); + } else if(field_type.kind == ECSACT_TYPE_KIND_FIELD_INDEX) { + auto compo_id = field_type.type.field_index.composite_id; + assoc_fields[compo_id].push_back(field_id); + assoc_composites[assoc_id].insert(compo_id); + } else { + // Should never get here. Association fields may only be an indexed + // field or entity field. + assert(false); + } + } } } @@ -84,35 +106,45 @@ auto provider::association::entity_iteration( make_view_opts.view_var_name = assoc_view_names.at(assoc_id); make_view_opts.registry_var_name = names.registry_var_name; + for(auto compo_id : assoc_composites.at(assoc_id)) { + } + util::make_view(ctx, make_view_opts); } + for(auto&& [assoc_id, compo_ids] : assoc_composites) { + for(auto compo_id : compo_ids) { + auto field_ids = assoc_fields.at(compo_id); + auto compo_cpp_ident = cpp_identifier(decl_full_name(compo_id)); + + ctx.write(std::format( + "{0}.storage({3}.storage<{1}>(static_cast<::entt::id_type>(::ecsact::" + "entt::detail::" + "hash_vals({1}::" + "id, {2}))));\n", + assoc_view_names.at(assoc_id), + compo_cpp_ident, + util::comma_delim( + field_ids | + std::views::transform([&](auto field_id) -> std::string { + return std::format( + "view.get<{}>(entity).{}", + compo_cpp_ident, + ecsact::meta::field_name(compo_id, field_id) + ); + }) + ), + names.registry_var_name + )); + } + } + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { auto assoc_comp_id = ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); auto assoc_field_ids = ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); auto assoc_comp_cpp_ident = cpp_identifier(decl_full_name(assoc_comp_id)); - - ctx.write(std::format( - "{0}.storage({3}.storage<{1}>(static_cast<::entt::id_type>(::ecsact::" - "entt::detail::" - "hash_vals({1}::" - "id, {2}))));\n", - assoc_view_names.at(assoc_id), - assoc_comp_cpp_ident, - util::comma_delim( - assoc_field_ids | - std::views::transform([&](auto field_id) -> std::string { - return std::format( - "view.get<{}>(entity).{}", - assoc_comp_cpp_ident, - ecsact::meta::field_name(assoc_comp_id, field_id) - ); - }) - ), - names.registry_var_name - )); } for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { diff --git a/rt_entt_codegen/core/system_provider/association/association.hh b/rt_entt_codegen/core/system_provider/association/association.hh index 674a2d1..1bf0a81 100644 --- a/rt_entt_codegen/core/system_provider/association/association.hh +++ b/rt_entt_codegen/core/system_provider/association/association.hh @@ -2,6 +2,7 @@ #include #include +#include #include "rt_entt_codegen/core/system_provider/system_provider.hh" #include "rt_entt_codegen/core/sys_exec/sys_exec.hh" #include "rt_entt_codegen/core/system_provider/system_ctx_functions.hh" @@ -53,7 +54,13 @@ public: ) -> handle_exclusive_provide final; private: - std::map assoc_view_names; + std::map assoc_view_names; + std::map> assoc_fields; + + // List of composites the association needs to read from in their view/group + // due to indexed fields. + std::map> + assoc_composites; auto print_other_contexts( ecsact::codegen_plugin_context& ctx, diff --git a/runtime/hash.cc b/runtime/hash.cc index 9b1b177..343b126 100644 --- a/runtime/hash.cc +++ b/runtime/hash.cc @@ -5,6 +5,24 @@ auto ecsact::entt::detail::bytes_hash( // std::byte* data, int data_length ) -> std::uint64_t { + if(data_length == sizeof(std::uint64_t)) { + auto bytes_as_u64 = std::uint64_t{}; + std::memcpy(&bytes_as_u64, data, sizeof(std::uint64_t)); + return bytes_as_u64; + } else if(data_length == sizeof(std::uint32_t)) { + auto bytes_as_u32 = std::uint32_t{}; + std::memcpy(&bytes_as_u32, data, sizeof(std::uint32_t)); + return bytes_as_u32; + } else if(data_length == sizeof(std::uint16_t)) { + auto bytes_as_u16 = std::uint16_t{}; + std::memcpy(&bytes_as_u16, data, sizeof(std::uint16_t)); + return bytes_as_u16; + } else if(data_length == 1) { + return static_cast(data[0]); + } else if(data_length == 0) { + return 0; + } + XXH64_hash_t hash = XXH3_64bits(data, data_length); return hash; } From d3c55fd10dac381fc3a5ceb54fe459a4f11ce666 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 20 Jun 2024 12:55:58 -0700 Subject: [PATCH 06/19] chore: update deps --- MODULE.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 78955b8..7b90e8d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,8 +7,8 @@ module( bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "bazel_skylib", version = "1.6.1") bazel_dep(name = "rules_ecsact", version = "0.5.2") -bazel_dep(name = "ecsact_runtime", version = "0.6.5") -bazel_dep(name = "ecsact_lang_cpp", version = "0.4.3") +bazel_dep(name = "ecsact_runtime", version = "0.6.6") +bazel_dep(name = "ecsact_lang_cpp", version = "0.4.4") bazel_dep(name = "boost.mp11", version = "1.83.0.bzl.1") bazel_dep(name = "entt", version = "3.12.2") bazel_dep(name = "ecsact_codegen", version = "0.2.0") From 3524506178c51042ab7cdcdf8d079319d5b331fd Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 21 Jun 2024 08:09:25 -0700 Subject: [PATCH 07/19] chore: wip --- ecsact/entt/detail/apply_pending.hh | 3 +- .../association/association.cc | 32 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ecsact/entt/detail/apply_pending.hh b/ecsact/entt/detail/apply_pending.hh index 2c2ec92..2262e6c 100644 --- a/ecsact/entt/detail/apply_pending.hh +++ b/ecsact/entt/detail/apply_pending.hh @@ -1,6 +1,7 @@ #pragma once #include +#include "ecsact/entt/registry.hh" #include "ecsact/entt/wrapper/core.hh" #include "ecsact/entt/detail/internal_markers.hh" @@ -10,7 +11,7 @@ template auto apply_pending_add(ecsact::entt::registry_t& registry) -> void { if constexpr(std::is_empty_v) { registry.view>().each([&](auto entity) { - C& comp = registry.emplace(entity); + registry.emplace(entity); // lifecycle_on_add(registry, entity, comp); }); } else { diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index eab28bf..406587c 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -65,22 +65,16 @@ auto provider::association::context_function_header( ); } +static auto push_back_unique(auto& vec, const auto& element) -> void { + if(std::ranges::find(vec, element) == std::end(vec)) { + vec.push_back(element); + } +} + auto provider::association::after_make_view_or_group( codegen_plugin_context& ctx, const common_vars& names ) -> void { - auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); - for(auto assoc_id : assoc_ids) { - auto assoc_caps = - ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); - auto assoc_system_details = - ecsact_entt_system_details::from_capabilities(assoc_caps); - auto make_view_opts = util::make_view_options(assoc_system_details); - make_view_opts.view_var_name = assoc_view_names.at(assoc_id); - make_view_opts.registry_var_name = names.registry_var_name; - - util::make_view(ctx, make_view_opts); - } } auto provider::association::context_function_other( @@ -107,11 +101,24 @@ auto provider::association::entity_iteration( make_view_opts.registry_var_name = names.registry_var_name; for(auto compo_id : assoc_composites.at(assoc_id)) { + // TODO: At the time of writing this is safe. It's very possible we + // allow actions to be referenecd in association fields in the near + // future and at that point this must be addressed. + auto comp_like_id = static_cast(compo_id); + if(!assoc_system_details.get_comps.contains(comp_like_id)) { + auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_like_id)); + push_back_unique( + make_view_opts.additional_components, + comp_cpp_ident + ); + } } util::make_view(ctx, make_view_opts); } + print_other_contexts(ctx, names); + for(auto&& [assoc_id, compo_ids] : assoc_composites) { for(auto compo_id : compo_ids) { auto field_ids = assoc_fields.at(compo_id); @@ -177,7 +184,6 @@ auto provider::association::pre_entity_iteration( codegen_plugin_context& ctx, const common_vars& names ) -> void { - print_other_contexts(ctx, names); } auto provider::association::pre_exec_system_impl( From 05daaf6a71b1c066bd51254d1a40abc3e642e24d Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 21 Jun 2024 11:54:15 -0700 Subject: [PATCH 08/19] fix: setup assoc globals and other contexts --- ecsact/entt/detail/apply_pending.hh | 2 +- .../entt/detail/system_execution_context.hh | 2 +- rt_entt_codegen/core/BUILD.bazel | 1 + rt_entt_codegen/core/assoc_globals.cc | 28 ++++++++++ rt_entt_codegen/core/core.hh | 5 ++ rt_entt_codegen/core/print_sys_exec.cc | 8 ++- .../association/association.cc | 51 +++++++++++-------- .../system_provider/system_ctx_functions.cc | 23 +++++++-- rt_entt_codegen/rt_entt_codegen.cc | 1 + rt_entt_codegen/shared/system_util.cc | 23 +++++++++ rt_entt_codegen/shared/system_util.hh | 30 ++++------- runtime/ecsact_rt_entt_dynamic.cc | 5 +- 12 files changed, 124 insertions(+), 55 deletions(-) create mode 100644 rt_entt_codegen/core/assoc_globals.cc diff --git a/ecsact/entt/detail/apply_pending.hh b/ecsact/entt/detail/apply_pending.hh index 2262e6c..b3cfe1d 100644 --- a/ecsact/entt/detail/apply_pending.hh +++ b/ecsact/entt/detail/apply_pending.hh @@ -1,7 +1,7 @@ #pragma once #include -#include "ecsact/entt/registry.hh" +#include "ecsact/entt/detail/registry.hh" #include "ecsact/entt/wrapper/core.hh" #include "ecsact/entt/detail/internal_markers.hh" diff --git a/ecsact/entt/detail/system_execution_context.hh b/ecsact/entt/detail/system_execution_context.hh index 16272fb..d3f6b9f 100644 --- a/ecsact/entt/detail/system_execution_context.hh +++ b/ecsact/entt/detail/system_execution_context.hh @@ -81,6 +81,6 @@ struct ecsact_system_execution_context { virtual auto parent() -> const ecsact_system_execution_context* = 0; virtual auto other( // - ecsact_entity_id entity + ecsact_system_assoc_id assoc_id ) -> ecsact_system_execution_context* = 0; }; diff --git a/rt_entt_codegen/core/BUILD.bazel b/rt_entt_codegen/core/BUILD.bazel index cd4b655..3108b65 100644 --- a/rt_entt_codegen/core/BUILD.bazel +++ b/rt_entt_codegen/core/BUILD.bazel @@ -47,6 +47,7 @@ _CORE_CODEGEN_METHODS = { ], "system_notify": ["//rt_entt_codegen/shared:system_util"], "update_beforechange": [], + "assoc_globals": [], } [cc_library( diff --git a/rt_entt_codegen/core/assoc_globals.cc b/rt_entt_codegen/core/assoc_globals.cc new file mode 100644 index 0000000..ede26d2 --- /dev/null +++ b/rt_entt_codegen/core/assoc_globals.cc @@ -0,0 +1,28 @@ +#include "rt_entt_codegen/core/core.hh" + +#include "ecsact/runtime/meta.hh" +#include "ecsact/lang-support/lang-cc.hh" + +using ecsact::cc_lang_support::c_identifier; +using ecsact::meta::decl_full_name; +using ecsact::meta::system_assoc_ids; + +auto ecsact::rt_entt_codegen::core::print_assoc_globals( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void { + for(auto sys_id : details.all_systems) { + auto assoc_ids = system_assoc_ids(sys_id); + for(auto i = 0; assoc_ids.size() > i; ++i) { + auto assoc_id = assoc_ids.at(i); + auto assoc_global_name = + std::format("{}__{}", c_identifier(decl_full_name(sys_id)), i); + ctx.write(std::format( + "extern \"C\" ecsact_system_assoc_id {} = " + "static_cast({});\n", + assoc_global_name, + i + )); + } + } +} diff --git a/rt_entt_codegen/core/core.hh b/rt_entt_codegen/core/core.hh index 532d98d..9970b85 100644 --- a/rt_entt_codegen/core/core.hh +++ b/rt_entt_codegen/core/core.hh @@ -6,6 +6,11 @@ namespace ecsact::rt_entt_codegen::core { +auto print_assoc_globals( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void; + auto print_parallel_system_execute( codegen_plugin_context& ctx, const ecsact_entt_details& details diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index c342a69..f987b63 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -32,6 +32,7 @@ template concept system_or_action = std::same_as || std::same_as; +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::comma_delim; @@ -222,7 +223,7 @@ auto print_sys_exec_ctx_other( ) -> void { auto printer = // method_printer{ctx, "other"} - .parameter("ecsact_entity_id", "entity") + .parameter("ecsact_system_assoc_id", "assoc_id") .return_type("ecsact_system_execution_context* final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { @@ -293,11 +294,8 @@ static auto print_system_execution_context( system_provider_t system_providers ) -> std::string { auto system_name = cpp_identifier(decl_full_name(sys_like_id)); - auto context_type_name = - ecsact::rt_entt_codegen::system_util::create_context_struct_name(sys_like_id - ); - + std::format("{}__Context", c_identifier(decl_full_name(sys_like_id))); auto struct_header = std::format( "struct {}: ecsact_system_execution_context ", context_type_name diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index 406587c..5967b07 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -1,5 +1,6 @@ #include "association.hh" +#include #include #include "ecsact/lang-support/lang-cc.hh" @@ -11,9 +12,10 @@ using ecsact::cc_lang_support::cpp_identifier; using ecsact::cpp_codegen_plugin_util::block; using ecsact::meta::decl_full_name; +using ecsact::meta::system_assoc_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::get_assoc_context_type_name; +using ecsact::rt_entt_codegen::system_util::get_assoc_context_var_name; using ecsact::rt_entt_codegen::system_util::get_unique_view_name; using ecsact::rt_entt_codegen::util::method_printer; @@ -58,11 +60,19 @@ auto provider::association::context_function_header( codegen_plugin_context& ctx, const common_vars& names ) -> void { - ctx.write( - "std::unordered_map " - "other_contexts;\n\n" - ); + auto assoc_ids = system_assoc_ids(sys_like_id); + + ctx.write("// Guaranteed order: "); + ctx.write(cpp_codegen_plugin_util::comma_delim( + assoc_ids | std::views::transform([&](auto assoc_id) -> std::string { + return get_assoc_context_type_name(sys_like_id, assoc_id); + }) + )); + ctx.write("\n"); + ctx.write(std::format( + "std::array other_contexts;\n\n", + assoc_ids.size() + )); } static auto push_back_unique(auto& vec, const auto& element) -> void { @@ -90,8 +100,10 @@ auto provider::association::entity_iteration( const common_vars& names, std::function iter_func ) -> handle_exclusive_provide { + auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + block(ctx, "for(auto entity : view)", [&] { - for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + for(auto assoc_id : assoc_ids) { auto assoc_caps = ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); auto assoc_system_details = @@ -146,19 +158,18 @@ auto provider::association::entity_iteration( } } - for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { - auto assoc_comp_id = - ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); - auto assoc_field_ids = - ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); - auto assoc_comp_cpp_ident = cpp_identifier(decl_full_name(assoc_comp_id)); - } - - for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + for(auto assoc_index = 0; assoc_ids.size() > assoc_index; ++assoc_index) { + auto assoc_id = assoc_ids.at(assoc_index); ctx.write(std::format( "auto {0}_itr = {0}.begin();\n", assoc_view_names.at(assoc_id) )); + + ctx.write(std::format( + "context.other_contexts[{}] = &{};\n", + assoc_index, + get_assoc_context_var_name(sys_like_id, assoc_id) + )); } block(ctx, "for(;;)", [&] { @@ -208,8 +219,8 @@ auto provider::association::print_other_contexts( for(auto assoc_id : assoc_ids) { auto assoc_comp_id = ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); - auto struct_name = create_context_struct_name(assoc_comp_id); - auto context_name = create_context_var_name(assoc_comp_id); + auto struct_name = get_assoc_context_type_name(sys_like_id, assoc_id); + auto context_name = get_assoc_context_var_name(sys_like_id, assoc_id); auto struct_header = struct_name + " : ecsact_system_execution_context "; auto assoc_caps = ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); @@ -375,7 +386,7 @@ auto provider::association::print_other_ctx_other( ) -> void { auto printer = // method_printer{ctx, "other"} - .parameter("ecsact_entity_id", "entity") + .parameter("ecsact_system_assoc_id", "assoc_id") .return_type("ecsact_system_execution_context* final"); context_other_impl(ctx, sys_like_id, details); diff --git a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc index 3e40980..dbadc20 100644 --- a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc +++ b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc @@ -402,10 +402,23 @@ auto ecsact::rt_entt_codegen::core::provider::context_other_impl( return; } - ctx.write( - "if(other_contexts.contains(entity)) {\n", - "return other_contexts.at(entity);\n}\n" - ); + if(details.association_details.size() == 1) { + ctx.write( + "// system has only 1 association. No other association ID should be " + "passed in here\n" + ); + ctx.write("assert(static_cast(assoc_id) == 0);\n"); + ctx.write("return other_contexts[0];\n"); + return; + } - ctx.write("return nullptr;\n"); + ctx.write(std::format( + "// system as {} associations and assoc_id is assumed to be an index\n", + details.association_details.size() + )); + ctx.write(std::format( + "assert(static_cast(assoc_id) < {});\n", + details.association_details.size() + )); + ctx.write("return other_contexts[static_cast(assoc_id)];\n"); } diff --git a/rt_entt_codegen/rt_entt_codegen.cc b/rt_entt_codegen/rt_entt_codegen.cc index a97ee07..044c135 100644 --- a/rt_entt_codegen/rt_entt_codegen.cc +++ b/rt_entt_codegen/rt_entt_codegen.cc @@ -234,6 +234,7 @@ void ecsact_codegen_plugin( { // Print core Ecsact API methods using namespace ecsact::rt_entt_codegen; + core::print_assoc_globals(ctx, details); core::print_entity_match_fn(ctx, details); core::print_system_marker_add_fn(ctx, details); core::print_system_marker_remove_fn(ctx, details); diff --git a/rt_entt_codegen/shared/system_util.cc b/rt_entt_codegen/shared/system_util.cc index 1dc8da3..7811271 100644 --- a/rt_entt_codegen/shared/system_util.cc +++ b/rt_entt_codegen/shared/system_util.cc @@ -5,6 +5,10 @@ #include "ecsact/runtime/common.h" +using namespace ecsact::rt_entt_codegen; +using ecsact::cc_lang_support::c_identifier; +using ecsact::meta::decl_full_name; + using capability_t = std::unordered_map; @@ -74,3 +78,22 @@ auto ecsact::rt_entt_codegen::system_util::get_unique_view_name() static int counter = 0; return "view" + std::to_string(counter++); } + +auto system_util::get_assoc_context_type_name( // + system_like_id_variant sys_like_id, + ecsact_system_assoc_id assoc_id +) -> std::string { + return std::format( + "{}__Context__{}", + c_identifier(decl_full_name(sys_like_id)), + static_cast(assoc_id) + ); +} + +auto system_util::get_assoc_context_var_name( // + system_like_id_variant, + ecsact_system_assoc_id assoc_id +) -> std::string { + // sys_like_id not used here - kept for potential future use + return std::format("assoc_context{}_", static_cast(assoc_id)); +} diff --git a/rt_entt_codegen/shared/system_util.hh b/rt_entt_codegen/shared/system_util.hh index 0b51ecd..8dea9bb 100644 --- a/rt_entt_codegen/shared/system_util.hh +++ b/rt_entt_codegen/shared/system_util.hh @@ -2,7 +2,7 @@ #include "ecsact/runtime/meta.hh" #include "ecsact/lang-support/lang-cc.hh" -#include "rt_entt_codegen/shared/system_variant.hh" +#include "system_variant.hh" namespace ecsact::rt_entt_codegen::system_util { @@ -19,24 +19,14 @@ 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"; -} +auto get_assoc_context_type_name( // + system_like_id_variant sys_like_id, + ecsact_system_assoc_id assoc_id +) -> std::string; + +auto get_assoc_context_var_name( // + system_like_id_variant sys_like_id, + ecsact_system_assoc_id assoc_id +) -> std::string; } // namespace ecsact::rt_entt_codegen::system_util diff --git a/runtime/ecsact_rt_entt_dynamic.cc b/runtime/ecsact_rt_entt_dynamic.cc index 8b5b829..848b819 100644 --- a/runtime/ecsact_rt_entt_dynamic.cc +++ b/runtime/ecsact_rt_entt_dynamic.cc @@ -60,10 +60,9 @@ ecsact_system_like_id ecsact_system_execution_context_id( ecsact_system_execution_context* ecsact_system_execution_context_other( ecsact_system_execution_context* context, - ecsact_entity_id entity_id + ecsact_system_assoc_id assoc_id ) { - assert(context != nullptr); - return context->other(entity_id); + return context->other(assoc_id); } void ecsact_system_execution_context_add( From 2fc27719c1d602c8afdc423079b6656043ab7fcd Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 21 Jun 2024 14:53:28 -0700 Subject: [PATCH 09/19] fix: adjusted after https://github.com/ecsact-dev/ecsact_runtime/pull/255 --- MODULE.bazel | 5 +++++ ecsact/entt/wrapper/core.hh | 18 ++++++++++++------ ecsact/entt/wrapper/dynamic.hh | 12 ++++++++---- rt_entt_codegen/core/assoc_globals.cc | 1 + rt_entt_codegen/core/print_sys_exec.cc | 2 ++ .../system_provider/association/association.cc | 8 ++++++++ .../system_provider/system_ctx_functions.cc | 8 ++++---- rt_entt_codegen/shared/system_util.cc | 1 + runtime/ecsact_rt_entt_core.cc | 12 ++++++++---- runtime/ecsact_rt_entt_dynamic.cc | 12 ++++++++---- 10 files changed, 57 insertions(+), 22 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 7b90e8d..c090911 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -20,6 +20,11 @@ local_path_override( path = "../ecsact_lang_cpp", ) +local_path_override( + module_name = "ecsact_runtime", + path = "../ecsact_runtime", +) + bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) bazel_dep(name = "hedron_compile_commands", dev_dependency = True) git_override( diff --git a/ecsact/entt/wrapper/core.hh b/ecsact/entt/wrapper/core.hh index 901cd1d..b326d8e 100644 --- a/ecsact/entt/wrapper/core.hh +++ b/ecsact/entt/wrapper/core.hh @@ -16,7 +16,8 @@ template inline auto has_component( // ecsact_registry_id registry_id, ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id + [[maybe_unused]] ecsact_component_id component_id, + ... ) -> bool { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; @@ -28,7 +29,8 @@ template inline auto get_component( ecsact_registry_id registry_id, ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id + [[maybe_unused]] ecsact_component_id component_id, + ... ) -> const void* { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; @@ -116,7 +118,8 @@ inline auto update_component( // ecsact_registry_id registry_id, ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, - const void* component_data + const void* component_data, + ... ) -> ecsact_update_error { using ecsact::entt::detail::exec_beforechange_storage; @@ -148,7 +151,8 @@ inline auto update_component_exec_options( // ecsact_registry_id registry_id, ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, - const void* component_data + const void* component_data, + ... ) -> ecsact_update_error { using ecsact::entt::detail::exec_beforechange_storage; @@ -184,7 +188,8 @@ template auto remove_component( ecsact_registry_id registry_id, ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id + [[maybe_unused]] ecsact_component_id component_id, + ... ) -> void { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; @@ -203,7 +208,8 @@ template auto remove_component_exec_options( ecsact_registry_id registry_id, ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id + [[maybe_unused]] ecsact_component_id component_id, + ... ) -> void { using ecsact::entt::detail::pending_remove; diff --git a/ecsact/entt/wrapper/dynamic.hh b/ecsact/entt/wrapper/dynamic.hh index 7007384..780a06f 100644 --- a/ecsact/entt/wrapper/dynamic.hh +++ b/ecsact/entt/wrapper/dynamic.hh @@ -70,7 +70,8 @@ template auto context_remove( ecsact_system_execution_context* context, [[maybe_unused]] ecsact_component_like_id component_id, - auto& view + auto& view, + ... ) -> void { assert(ecsact_id_cast(C::id) == component_id); @@ -125,7 +126,8 @@ auto context_get( ecsact_system_execution_context* context, [[maybe_unused]] ecsact_component_like_id component_id, void* out_component_data, - auto& view + auto& view, + ... ) -> void { auto entity = context->entity; @@ -137,7 +139,8 @@ auto context_update( ecsact_system_execution_context* context, [[maybe_unused]] ecsact_component_like_id component_id, const void* in_component_data, - auto& view + auto& view, + ... ) -> void { using ecsact::entt::detail::exec_beforechange_storage; // TODO(Kelwan): for remove, beforeremove_storage @@ -158,7 +161,8 @@ auto context_update( template auto context_has( ecsact_system_execution_context* context, - [[maybe_unused]] ecsact_component_like_id component_id + [[maybe_unused]] ecsact_component_like_id component_id, + ... ) -> bool { auto entity = context->entity; auto& registry = *context->registry; diff --git a/rt_entt_codegen/core/assoc_globals.cc b/rt_entt_codegen/core/assoc_globals.cc index ede26d2..97db9e3 100644 --- a/rt_entt_codegen/core/assoc_globals.cc +++ b/rt_entt_codegen/core/assoc_globals.cc @@ -1,5 +1,6 @@ #include "rt_entt_codegen/core/core.hh" +#include #include "ecsact/runtime/meta.hh" #include "ecsact/lang-support/lang-cc.hh" diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index f987b63..16a4fa1 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -544,6 +544,7 @@ static auto print_execute_system_template_specialization( ); block(ctx, "if(system_impl == nullptr)", [&] { ctx.write("return;"); }); + ctx.write("\n"); print_execute_systems( ctx, @@ -594,6 +595,7 @@ static auto print_execute_actions_template_specialization( ); block(ctx, "if(system_impl == nullptr)", [&] { ctx.write("return;"); }); + ctx.write("\n"); ctx.write( "auto actions = actions_map.as_action_span<", diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index 5967b07..bb320f8 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -180,6 +180,14 @@ auto provider::association::entity_iteration( )); } + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + ctx.write(std::format( + "{}.entity = *{}_itr;\n", + get_assoc_context_var_name(sys_like_id, assoc_id), + assoc_view_names.at(assoc_id) + )); + } + iter_func(); for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { diff --git a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc index dbadc20..abec590 100644 --- a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc +++ b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc @@ -196,7 +196,7 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl( ctx.write(std::format( "using get_fn_t = void (*)(ecsact_system_execution_context*, " - "ecsact_component_like_id, void *, {}_t&);\n", + "ecsact_component_like_id, void *, {}_t&, ...);\n", view_type_name )); @@ -253,7 +253,7 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl( ctx.write(std::format( "using update_fn_t = void (*)(ecsact_system_execution_context*, " - "ecsact_component_like_id, const void *, {}_t&);\n", + "ecsact_component_like_id, const void *, {}_t&, ...);\n", view_type_name )); @@ -408,7 +408,7 @@ auto ecsact::rt_entt_codegen::core::provider::context_other_impl( "passed in here\n" ); ctx.write("assert(static_cast(assoc_id) == 0);\n"); - ctx.write("return other_contexts[0];\n"); + ctx.write("return other_contexts[0];"); return; } @@ -420,5 +420,5 @@ auto ecsact::rt_entt_codegen::core::provider::context_other_impl( "assert(static_cast(assoc_id) < {});\n", details.association_details.size() )); - ctx.write("return other_contexts[static_cast(assoc_id)];\n"); + ctx.write("return other_contexts[static_cast(assoc_id)];"); } diff --git a/rt_entt_codegen/shared/system_util.cc b/rt_entt_codegen/shared/system_util.cc index 7811271..b4e77dc 100644 --- a/rt_entt_codegen/shared/system_util.cc +++ b/rt_entt_codegen/shared/system_util.cc @@ -1,6 +1,7 @@ #include "system_util.hh" #include +#include #include #include "ecsact/runtime/common.h" diff --git a/runtime/ecsact_rt_entt_core.cc b/runtime/ecsact_rt_entt_core.cc index 8418c56..7dea449 100644 --- a/runtime/ecsact_rt_entt_core.cc +++ b/runtime/ecsact_rt_entt_core.cc @@ -109,7 +109,8 @@ ecsact_add_error ecsact_add_component( bool ecsact_has_component( ecsact_registry_id reg_id, ecsact_entity_id entity_id, - ecsact_component_id component_id + ecsact_component_id component_id, + ... ) { using ecsact::entt::detail::globals::has_component_fns; auto fn_itr = has_component_fns.find(component_id); @@ -120,7 +121,8 @@ bool ecsact_has_component( const void* ecsact_get_component( ecsact_registry_id reg_id, ecsact_entity_id entity_id, - ecsact_component_id component_id + ecsact_component_id component_id, + ... ) { using ecsact::entt::detail::globals::get_component_fns; auto fn_itr = get_component_fns.find(component_id); @@ -195,7 +197,8 @@ ecsact_update_error ecsact_update_component( ecsact_registry_id reg_id, ecsact_entity_id entity_id, ecsact_component_id component_id, - const void* component_data + const void* component_data, + ... ) { using ecsact::entt::detail::globals::update_component_fns; auto fn_itr = update_component_fns.find(component_id); @@ -206,7 +209,8 @@ ecsact_update_error ecsact_update_component( void ecsact_remove_component( ecsact_registry_id reg_id, ecsact_entity_id entity_id, - ecsact_component_id component_id + ecsact_component_id component_id, + ... ) { using ecsact::entt::detail::globals::remove_component_fns; auto fn_itr = remove_component_fns.find(component_id); diff --git a/runtime/ecsact_rt_entt_dynamic.cc b/runtime/ecsact_rt_entt_dynamic.cc index 848b819..fff9489 100644 --- a/runtime/ecsact_rt_entt_dynamic.cc +++ b/runtime/ecsact_rt_entt_dynamic.cc @@ -76,7 +76,8 @@ void ecsact_system_execution_context_add( void ecsact_system_execution_context_remove( ecsact_system_execution_context* context, - ecsact_component_like_id comp_id + ecsact_component_like_id comp_id, + ... ) { assert(context != nullptr); return context->remove(comp_id); @@ -85,7 +86,8 @@ void ecsact_system_execution_context_remove( void ecsact_system_execution_context_get( ecsact_system_execution_context* context, ecsact_component_like_id comp_id, - void* out_component_data + void* out_component_data, + ... ) { assert(context != nullptr); return context->get(comp_id, out_component_data); @@ -94,7 +96,8 @@ void ecsact_system_execution_context_get( void ecsact_system_execution_context_update( ecsact_system_execution_context* context, ecsact_component_like_id comp_id, - const void* component_data + const void* component_data, + ... ) { assert(context != nullptr); return context->update(comp_id, component_data); @@ -102,7 +105,8 @@ void ecsact_system_execution_context_update( bool ecsact_system_execution_context_has( ecsact_system_execution_context* context, - ecsact_component_like_id comp_id + ecsact_component_like_id comp_id, + ... ) { assert(context != nullptr); return context->has(comp_id); From 12eb9c74e0c6d12f355e33ad39721b13388a57e3 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 21 Jun 2024 17:47:27 -0700 Subject: [PATCH 10/19] feat: passing around field assoc hash as a param --- ecsact/entt/detail/assoc_fields_hash.hh | 12 ++ ecsact/entt/detail/globals.hh | 116 +++++++----------- .../entt/detail/system_execution_context.hh | 12 +- ecsact/entt/wrapper/core.hh | 35 +++++- ecsact/entt/wrapper/dynamic.hh | 8 +- rt_entt_codegen/core/BUILD.bazel | 2 +- rt_entt_codegen/core/assoc_fields_hash.cc | 92 ++++++++++++++ rt_entt_codegen/core/core.hh | 5 + rt_entt_codegen/core/execution_options.cc | 12 +- rt_entt_codegen/core/print_sys_exec.cc | 4 + .../association/association.cc | 4 + .../system_provider/system_ctx_functions.cc | 24 ++-- rt_entt_codegen/rt_entt_codegen.cc | 2 + runtime/ecsact_rt_entt_core.cc | 56 ++++++++- runtime/ecsact_rt_entt_dynamic.cc | 50 +++++++- 15 files changed, 321 insertions(+), 113 deletions(-) create mode 100644 ecsact/entt/detail/assoc_fields_hash.hh create mode 100644 rt_entt_codegen/core/assoc_fields_hash.cc diff --git a/ecsact/entt/detail/assoc_fields_hash.hh b/ecsact/entt/detail/assoc_fields_hash.hh new file mode 100644 index 0000000..ed8b6d1 --- /dev/null +++ b/ecsact/entt/detail/assoc_fields_hash.hh @@ -0,0 +1,12 @@ +#pragma once + +#include +#include +#include "ecsact/runtime/common.h" + +namespace ecsact::entt::detail { +auto get_assoc_fields_hash( + ecsact_composite_id compo_id, + std::va_list indexed_field_values +) -> std::uint64_t; +} diff --git a/ecsact/entt/detail/globals.hh b/ecsact/entt/detail/globals.hh index 791da4c..6ff2e5b 100644 --- a/ecsact/entt/detail/globals.hh +++ b/ecsact/entt/detail/globals.hh @@ -41,6 +41,13 @@ extern std::unordered_map< // */ extern const std::unordered_set all_component_ids; +using add_component_fn_sig_t = ecsact_add_error (*)( + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + const void* component_data +); + /** * ecsact_add_component fn pointers * @@ -48,9 +55,16 @@ extern const std::unordered_set all_component_ids; */ extern const std::unordered_map< // ecsact_component_id, - decltype(&ecsact_add_component)> + add_component_fn_sig_t> add_component_fns; +using get_component_fn_sig_t = const void* (*)( // + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + std::uint64_t assoc_fields_hash +); + /** * ecsact_get_component fn pointers * @@ -58,9 +72,17 @@ extern const std::unordered_map< // */ extern const std::unordered_map< // ecsact_component_id, - decltype(&ecsact_get_component)> + get_component_fn_sig_t> get_component_fns; +using update_component_fn_sig_t = ecsact_update_error (*)( + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + const void* component_data, + std::uint64_t assoc_fields_hash +); + /** * ecsact_update_component fn pointers * @@ -68,9 +90,16 @@ extern const std::unordered_map< // */ extern const std::unordered_map< // ecsact_component_id, - decltype(&ecsact_update_component)> + update_component_fn_sig_t> update_component_fns; +using remove_component_fn_sig_t = void (*)( + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + std::uint64_t assoc_fields_hash +); + /** * ecsact_remove_component fn pointers * @@ -78,9 +107,16 @@ extern const std::unordered_map< // */ extern const std::unordered_map< // ecsact_component_id, - decltype(&ecsact_remove_component)> + remove_component_fn_sig_t> remove_component_fns; +using has_component_fn_sig_t = bool (*)( + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + std::uint64_t assoc_fields_hash +); + /** * ecsact_has_component fn pointers * @@ -88,79 +124,9 @@ extern const std::unordered_map< // */ extern const std::unordered_map< // ecsact_component_id, - decltype(&ecsact_has_component)> + has_component_fn_sig_t> has_component_fns; -/** - * ecsact_system_execution_context_get fn pointers - * - * NOTE: This gets is filled in by ecsact_rt_entt_codegen - */ -extern const std::unordered_map< // - ecsact_system_like_id, - std::unordered_map< - ecsact::entt::assoc_index, - std::unordered_map< // - ecsact_component_like_id, - decltype(&ecsact_system_execution_context_get)>>> - exec_ctx_get_fns; - -/** - * ecsact_system_execution_context_add fn pointers - * - * NOTE: This adds is filled in by ecsact_rt_entt_codegen - */ -extern const std::unordered_map< // - ecsact_system_like_id, - std::unordered_map< - ecsact::entt::assoc_index, - std::unordered_map< // - ecsact_component_like_id, - decltype(&ecsact_system_execution_context_add)>>> - exec_ctx_add_fns; - -/** - * ecsact_system_execution_context_update fn pointers - * - * NOTE: This updates is filled in by ecsact_rt_entt_codegen - */ -extern const std::unordered_map< // - ecsact_system_like_id, - std::unordered_map< - ecsact::entt::assoc_index, - std::unordered_map< // - ecsact_component_like_id, - decltype(&ecsact_system_execution_context_update)>>> - exec_ctx_update_fns; - -/** - * ecsact_system_execution_context_remove fn pointers - * - * NOTE: This removes is filled in by ecsact_rt_entt_codegen - */ -extern const std::unordered_map< // - ecsact_system_like_id, - std::unordered_map< - ecsact::entt::assoc_index, - std::unordered_map< // - ecsact_component_like_id, - decltype(&ecsact_system_execution_context_remove)>>> - exec_ctx_remove_fns; - -/** - * ecsact_system_execution_context_has fn pointers - * - * NOTE: This has is filled in by ecsact_rt_entt_codegen - */ -extern const std::unordered_map< // - ecsact_system_like_id, - std::unordered_map< - ecsact::entt::assoc_index, - std::unordered_map< // - ecsact_component_like_id, - decltype(&ecsact_system_execution_context_has)>>> - exec_ctx_has_fns; - /** * ecsact_system_execution_context_action fn pointers * diff --git a/ecsact/entt/detail/system_execution_context.hh b/ecsact/entt/detail/system_execution_context.hh index d3f6b9f..9d53593 100644 --- a/ecsact/entt/detail/system_execution_context.hh +++ b/ecsact/entt/detail/system_execution_context.hh @@ -55,21 +55,25 @@ struct ecsact_system_execution_context { ) -> void = 0; virtual auto remove( // - ecsact_component_like_id component_id + ecsact_component_like_id component_id, + std::uint64_t assoc_fields_hash ) -> void = 0; virtual auto get( // ecsact_component_like_id component_id, - void* out_component_data + void* out_component_data, + std::uint64_t assoc_fields_hash ) -> void = 0; virtual auto update( // ecsact_component_like_id component_id, - const void* component_data + const void* component_data, + std::uint64_t assoc_fields_hash ) -> void = 0; virtual auto has( // - ecsact_component_like_id component_id + ecsact_component_like_id component_id, + std::uint64_t assoc_fields_hash ) -> bool = 0; virtual auto generate( // diff --git a/ecsact/entt/wrapper/core.hh b/ecsact/entt/wrapper/core.hh index b326d8e..0b7614f 100644 --- a/ecsact/entt/wrapper/core.hh +++ b/ecsact/entt/wrapper/core.hh @@ -17,7 +17,7 @@ inline auto has_component( // ecsact_registry_id registry_id, ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, - ... + std::uint64_t assoc_fields_hash ) -> bool { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; @@ -30,7 +30,7 @@ inline auto get_component( ecsact_registry_id registry_id, ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, - ... + std::uint64_t assoc_fields_hash ) -> const void* { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; @@ -119,7 +119,7 @@ inline auto update_component( // ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, const void* component_data, - ... + std::uint64_t assoc_fields_hash ) -> ecsact_update_error { using ecsact::entt::detail::exec_beforechange_storage; @@ -146,13 +146,21 @@ inline auto update_component( // return err; } +using update_component_exec_options_sig_t = ecsact_update_error (*)( // + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + const void* component_data, + std::uint64_t assoc_fields_hash +); + template inline auto update_component_exec_options( // ecsact_registry_id registry_id, ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, const void* component_data, - ... + std::uint64_t assoc_fields_hash ) -> ecsact_update_error { using ecsact::entt::detail::exec_beforechange_storage; @@ -184,12 +192,16 @@ inline auto update_component_exec_options( // return err; } +static_assert(std::is_same_v< + update_component_exec_options_sig_t, + decltype(&update_component_exec_options)>); + template auto remove_component( ecsact_registry_id registry_id, ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, - ... + std::uint64_t assoc_fields_hash ) -> void { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; @@ -204,12 +216,19 @@ auto remove_component( ecsact::entt::detail::remove_system_markers_if_needed(reg, entity); } +using remove_component_exec_options_sig_t = void (*)( // + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + std::uint64_t assoc_fields_hash +); + template auto remove_component_exec_options( ecsact_registry_id registry_id, ecsact_entity_id entity_id, [[maybe_unused]] ecsact_component_id component_id, - ... + std::uint64_t assoc_fields_hash ) -> void { using ecsact::entt::detail::pending_remove; @@ -235,6 +254,10 @@ auto remove_component_exec_options( ecsact::entt::detail::remove_system_markers_if_needed(reg, entity); } +static_assert(std::is_same_v< + remove_component_exec_options_sig_t, + decltype(&remove_component_exec_options)>); + inline auto _trigger_create_entity_events( ecsact_registry_id registry_id, ecsact::entt::detail::execution_events_collector& events_collector diff --git a/ecsact/entt/wrapper/dynamic.hh b/ecsact/entt/wrapper/dynamic.hh index 780a06f..bb7a329 100644 --- a/ecsact/entt/wrapper/dynamic.hh +++ b/ecsact/entt/wrapper/dynamic.hh @@ -71,7 +71,7 @@ auto context_remove( ecsact_system_execution_context* context, [[maybe_unused]] ecsact_component_like_id component_id, auto& view, - ... + std::uint64_t assoc_fields_hash ) -> void { assert(ecsact_id_cast(C::id) == component_id); @@ -127,7 +127,7 @@ auto context_get( [[maybe_unused]] ecsact_component_like_id component_id, void* out_component_data, auto& view, - ... + std::uint64_t assoc_fields_hash ) -> void { auto entity = context->entity; @@ -140,7 +140,7 @@ auto context_update( [[maybe_unused]] ecsact_component_like_id component_id, const void* in_component_data, auto& view, - ... + std::uint64_t assoc_fields_hash ) -> void { using ecsact::entt::detail::exec_beforechange_storage; // TODO(Kelwan): for remove, beforeremove_storage @@ -162,7 +162,7 @@ template auto context_has( ecsact_system_execution_context* context, [[maybe_unused]] ecsact_component_like_id component_id, - ... + std::uint64_t assoc_fields_hash ) -> bool { auto entity = context->entity; auto& registry = *context->registry; diff --git a/rt_entt_codegen/core/BUILD.bazel b/rt_entt_codegen/core/BUILD.bazel index 3108b65..a45dbb9 100644 --- a/rt_entt_codegen/core/BUILD.bazel +++ b/rt_entt_codegen/core/BUILD.bazel @@ -11,6 +11,7 @@ cc_library( # keep sorted _CORE_CODEGEN_METHODS = { + "assoc_fields_hash": [], "execute_systems": [ "//rt_entt_codegen/shared:parallel", "//rt_entt_codegen/shared:system_variant", @@ -33,7 +34,6 @@ _CORE_CODEGEN_METHODS = { "//rt_entt_codegen/core/system_provider:basic", "//rt_entt_codegen/core/system_provider:parallel", "//rt_entt_codegen/core/system_provider", - "@entt//:entt", "@ecsact_rt_entt//:lib", ], "check_error": [], diff --git a/rt_entt_codegen/core/assoc_fields_hash.cc b/rt_entt_codegen/core/assoc_fields_hash.cc new file mode 100644 index 0000000..a48332d --- /dev/null +++ b/rt_entt_codegen/core/assoc_fields_hash.cc @@ -0,0 +1,92 @@ + +#include "rt_entt_codegen/core/core.hh" + +#include +#include +#include "ecsact/runtime/meta.hh" +#include "ecsact/lang-support/lang-cc.hh" +#include "ecsact/cpp_codegen_plugin_util.hh" + +using ecsact::cc_lang_support::c_identifier; +using ecsact::cc_lang_support::cpp_field_type_name; +using ecsact::cc_lang_support::cpp_identifier; +using ecsact::cpp_codegen_plugin_util::block; +using ecsact::cpp_codegen_plugin_util::comma_delim; +using ecsact::cpp_codegen_plugin_util::method_printer; +using ecsact::meta::decl_full_name; +using ecsact::meta::system_assoc_ids; + +template +static auto get_assoc_fields(CompositeID compo_id +) -> std::vector { + auto result = std::vector{}; + + for(auto field_id : ecsact::meta::get_field_ids(compo_id)) { + auto field_type = ecsact::meta::get_field_type(compo_id, field_id); + if(field_type.kind == ECSACT_TYPE_KIND_BUILTIN && + field_type.type.builtin == ECSACT_ENTITY_TYPE) { + result.push_back(field_id); + } + + if(field_type.kind == ECSACT_TYPE_KIND_FIELD_INDEX) { + result.push_back(field_id); + } + } + + return result; +} + +auto ecsact::rt_entt_codegen::core::print_assoc_fields_hash( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void { + auto printer = // + method_printer{ctx, "ecsact::entt::detail::get_assoc_fields_hash"} // + .parameter("ecsact_composite_id", "compo_id") + .parameter("std::va_list", "indexed_field_values") + .return_type("std::uint64_t"); + + for(auto comp_id : details.all_components) { + auto compo_cpp_identifier = cpp_identifier(decl_full_name(comp_id)); + auto assoc_fields = get_assoc_fields(comp_id); + if(assoc_fields.empty()) { + continue; + } + + block( + ctx, + std::format( + "if(ecsact_id_cast({}::id) == compo_id)", + compo_cpp_identifier + ), + [&] { + for(auto field_id : assoc_fields) { + auto field_name = ecsact::meta::field_name(comp_id, field_id); + auto field_type = ecsact::meta::get_field_type(comp_id, field_id); + auto field_cpp_type = cpp_field_type_name(field_type); + ctx.write(std::format( + "auto {} = va_arg(indexed_field_values, {});\n", + field_name, + field_cpp_type + )); + } + + ctx.write(std::format( + "return " + "::ecsact::entt::detail::hash_vals(static_cast({}::id), " + "{});", + compo_cpp_identifier, + comma_delim(std::views::transform( + assoc_fields, + [&](auto field_id) -> std::string { + return ecsact::meta::field_name(comp_id, field_id); + } + )) + )); + } + ); + ctx.write("\n"); + } + + ctx.write("return 0;"); +} diff --git a/rt_entt_codegen/core/core.hh b/rt_entt_codegen/core/core.hh index 9970b85..537f3b5 100644 --- a/rt_entt_codegen/core/core.hh +++ b/rt_entt_codegen/core/core.hh @@ -6,6 +6,11 @@ namespace ecsact::rt_entt_codegen::core { +auto print_assoc_fields_hash( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void; + auto print_assoc_globals( codegen_plugin_context& ctx, const ecsact_entt_details& details diff --git a/rt_entt_codegen/core/execution_options.cc b/rt_entt_codegen/core/execution_options.cc index 636e02d..17a53b6 100644 --- a/rt_entt_codegen/core/execution_options.cc +++ b/rt_entt_codegen/core/execution_options.cc @@ -39,7 +39,7 @@ inline auto print_static_maps( ctx, "static const auto execution_update_fns=" "std::unordered_map\n", + "ecsact::entt::wrapper::core::update_component_exec_options_sig_t>\n", [&] { for(auto component_id : details.all_components) { auto type_name = cpp_identifier(decl_full_name(component_id)); @@ -68,7 +68,7 @@ inline auto print_static_maps( ctx, "static const auto execution_remove_fns= " "std::unordered_map\n", + "ecsact::entt::wrapper::core::remove_component_exec_options_sig_t>\n", [&] { for(auto component_id : details.all_components) { auto type_name = cpp_identifier(decl_full_name(component_id)); @@ -179,25 +179,27 @@ auto ecsact::rt_entt_codegen::core::print_execution_options( block(ctx, "for(int i = 0; i < options.update_components_length; i++)", [&] { ctx.write("auto& component = options.update_components[i];\n"); - ctx.write("auto entity = options.update_components_entities[i];\n\n"); + ctx.write("auto entity = options.update_components_entities[i];\n"); + ctx.write("auto assoc_fields_hash = std::uint64_t{}; // TODO\n\n"); ctx.write( "execution_update_fns.at(ecsact_id_cast(" "component.component_id))(registry_id, " "ecsact::entt::entity_id(entity), " - "component.component_id, component.component_data);\n" + "component.component_id, component.component_data, assoc_fields_hash);\n" ); }); block(ctx, "for(int i = 0; i < options.remove_components_length; i++)", [&] { ctx.write("auto& component_id = options.remove_components[i];\n"); ctx.write("auto entity = options.remove_components_entities[i];\n\n"); + ctx.write("auto assoc_fields_hash = std::uint64_t{}; // TODO\n\n"); ctx.write( "execution_remove_fns.at(ecsact_id_cast(" "component_id))(registry_id, " "ecsact::entt::entity_id(entity), " - "component_id);\n\n" + "component_id, assoc_fields_hash);\n\n" ); }); diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index 16a4fa1..6f6dfd2 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -100,6 +100,7 @@ static auto print_sys_exec_ctx_remove( auto printer = // method_printer{ctx, "remove"} .parameter("ecsact_component_like_id", "component_id") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("void final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { @@ -121,6 +122,7 @@ static auto print_sys_exec_ctx_get( method_printer{ctx, "get"} .parameter("ecsact_component_like_id", "component_id") .parameter("void*", "out_component_data") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("void final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { @@ -142,6 +144,7 @@ static auto print_sys_exec_ctx_update( method_printer{ctx, "update"} .parameter("ecsact_component_like_id", "component_id") .parameter("const void*", "component_data") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("void final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { @@ -162,6 +165,7 @@ static auto print_sys_exec_ctx_has( auto printer = // method_printer{ctx, "has"} .parameter("ecsact_component_like_id", "component_id") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("bool final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index bb320f8..3cdffdd 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -318,6 +318,7 @@ auto provider::association::print_other_ctx_remove( auto printer = // method_printer{ctx, "remove"} .parameter("ecsact_component_like_id", "component_id") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("void final"); context_remove_impl(ctx, other_caps, details, view_type_name); @@ -332,6 +333,7 @@ auto provider::association::print_other_ctx_get( method_printer{ctx, "get"} .parameter("ecsact_component_like_id", "component_id") .parameter("void*", "out_component_data") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("void final"); context_get_impl(ctx, sys_like_id, details, view_type_name); @@ -346,6 +348,7 @@ auto provider::association::print_other_ctx_update( method_printer{ctx, "update"} .parameter("ecsact_component_like_id", "component_id") .parameter("const void*", "component_data") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("void final"); context_update_impl(ctx, sys_like_id, details, view_type_name); @@ -358,6 +361,7 @@ auto provider::association::print_other_ctx_has( auto printer = // method_printer{ctx, "has"} .parameter("ecsact_component_like_id", "component_id") + .parameter("std::uint64_t", "assoc_fields_hash") .return_type("bool final"); context_has_impl(ctx, sys_like_id, details); diff --git a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc index abec590..35433fa 100644 --- a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc +++ b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc @@ -118,7 +118,7 @@ auto ecsact::rt_entt_codegen::core::provider::context_remove_impl( type_name, ">(this, ecsact_id_cast(", type_name, - "::id), *view);\n" + "::id), *view, assoc_fields_hash);\n" ); return; } @@ -148,7 +148,7 @@ auto ecsact::rt_entt_codegen::core::provider::context_remove_impl( ctx.write("return result;\n"); }); - ctx.write("();\n"); + ctx.write("(assoc_fields_hash);\n"); } auto ecsact::rt_entt_codegen::core::provider::context_get_impl( @@ -196,7 +196,7 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl( ctx.write(std::format( "using get_fn_t = void (*)(ecsact_system_execution_context*, " - "ecsact_component_like_id, void *, {}_t&, ...);\n", + "ecsact_component_like_id, void *, {}_t&, std::uint64_t);\n", view_type_name )); @@ -223,7 +223,8 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl( ctx.write("();\n"); ctx.write( - "get_fns.at(component_id)(this, component_id, out_component_data, *view);\n" + "get_fns.at(component_id)(this, component_id, out_component_data, *view, " + "assoc_fields_hash);\n" ); } @@ -246,14 +247,14 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl( ">(this, ecsact_id_cast(", type_name, "::id),", - "component_data, *view); \n" + "component_data, *view, assoc_fields_hash); \n" ); return; } ctx.write(std::format( "using update_fn_t = void (*)(ecsact_system_execution_context*, " - "ecsact_component_like_id, const void *, {}_t&, ...);\n", + "ecsact_component_like_id, const void *, {}_t&, std::uint64_t);\n", view_type_name )); @@ -281,7 +282,7 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl( ctx.write( "update_fns.at(component_id)(this, component_id, component_data, " - "*view);\n" + "*view, assoc_fields_hash);\n" ); } @@ -303,14 +304,15 @@ auto ecsact::rt_entt_codegen::core::provider::context_has_impl( type_name, ">(this, ecsact_id_cast(", type_name, - "::id));\n" + "::id), assoc_fields_hash);" ); + return; } block( ctx, "static const auto has_fns = " "std::unordered_map", + "decltype(&wrapper::dynamic::context_has)>", [&] { for(const auto comp_id : details.readable_comps) { auto type_name = cpp_identifier(decl_full_name(comp_id)); @@ -326,7 +328,9 @@ auto ecsact::rt_entt_codegen::core::provider::context_has_impl( ); ctx.write(";\n"); - ctx.write("return has_fns.at(component_id)(this, component_id);\n"); + ctx.write( + "return has_fns.at(component_id)(this, component_id, assoc_fields_hash);" + ); } auto ecsact::rt_entt_codegen::core::provider::context_generate_impl( diff --git a/rt_entt_codegen/rt_entt_codegen.cc b/rt_entt_codegen/rt_entt_codegen.cc index 044c135..9076495 100644 --- a/rt_entt_codegen/rt_entt_codegen.cc +++ b/rt_entt_codegen/rt_entt_codegen.cc @@ -50,6 +50,7 @@ void ecsact_codegen_plugin( inc_header(ctx, "ecsact/entt/execution.hh"); inc_header(ctx, "ecsact/entt/registry_util.hh"); inc_header(ctx, "ecsact/entt/detail/globals.hh"); + inc_header(ctx, "ecsact/entt/detail/assoc_fields_hash.hh"); inc_header(ctx, "ecsact/entt/detail/apply_pending.hh"); inc_header(ctx, "ecsact/entt/detail/registry.hh"); inc_header(ctx, "ecsact/entt/detail/bytes.hh"); @@ -234,6 +235,7 @@ void ecsact_codegen_plugin( { // Print core Ecsact API methods using namespace ecsact::rt_entt_codegen; + core::print_assoc_fields_hash(ctx, details); core::print_assoc_globals(ctx, details); core::print_entity_match_fn(ctx, details); core::print_system_marker_add_fn(ctx, details); diff --git a/runtime/ecsact_rt_entt_core.cc b/runtime/ecsact_rt_entt_core.cc index 7dea449..a676f8f 100644 --- a/runtime/ecsact_rt_entt_core.cc +++ b/runtime/ecsact_rt_entt_core.cc @@ -6,11 +6,21 @@ * derived from the input Ecsact files they will not be defined here. */ +#include #include "ecsact/runtime/core.h" #include "ecsact/entt/detail/globals.hh" +#include "ecsact/entt/detail/assoc_fields_hash.hh" #include "ecsact/entt/registry_util.hh" #include "ecsact/entt/entity.hh" +#ifdef __clang__ +static_assert(true, "workaround https://github.com/clangd/clangd/issues/1167"); +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Winconsistent-dllimport" +#endif + +using ecsact::entt::detail::get_assoc_fields_hash; + void ecsact_destroy_registry(ecsact_registry_id reg_id) { auto& reg = ecsact::entt::get_registry(reg_id); reg = {}; @@ -113,9 +123,16 @@ bool ecsact_has_component( ... ) { using ecsact::entt::detail::globals::has_component_fns; + std::va_list indexed_fields; + va_start(indexed_fields, component_id); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(component_id), + indexed_fields + ); + va_end(indexed_fields); auto fn_itr = has_component_fns.find(component_id); assert(fn_itr != has_component_fns.end()); - return fn_itr->second(reg_id, entity_id, component_id); + return fn_itr->second(reg_id, entity_id, component_id, assoc_fields_hash); } const void* ecsact_get_component( @@ -125,9 +142,16 @@ const void* ecsact_get_component( ... ) { using ecsact::entt::detail::globals::get_component_fns; + std::va_list indexed_fields; + va_start(indexed_fields, component_id); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(component_id), + indexed_fields + ); + va_end(indexed_fields); auto fn_itr = get_component_fns.find(component_id); assert(fn_itr != get_component_fns.end()); - return fn_itr->second(reg_id, entity_id, component_id); + return fn_itr->second(reg_id, entity_id, component_id, assoc_fields_hash); } int ecsact_count_components( @@ -201,9 +225,22 @@ ecsact_update_error ecsact_update_component( ... ) { using ecsact::entt::detail::globals::update_component_fns; + std::va_list indexed_fields; + va_start(indexed_fields, component_data); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(component_id), + indexed_fields + ); + va_end(indexed_fields); auto fn_itr = update_component_fns.find(component_id); assert(fn_itr != update_component_fns.end()); - return fn_itr->second(reg_id, entity_id, component_id, component_data); + return fn_itr->second( + reg_id, + entity_id, + component_id, + component_data, + assoc_fields_hash + ); } void ecsact_remove_component( @@ -213,7 +250,18 @@ void ecsact_remove_component( ... ) { using ecsact::entt::detail::globals::remove_component_fns; + std::va_list indexed_fields; + va_start(indexed_fields, component_id); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(component_id), + indexed_fields + ); + va_end(indexed_fields); auto fn_itr = remove_component_fns.find(component_id); assert(fn_itr != remove_component_fns.end()); - return fn_itr->second(reg_id, entity_id, component_id); + return fn_itr->second(reg_id, entity_id, component_id, assoc_fields_hash); } + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif diff --git a/runtime/ecsact_rt_entt_dynamic.cc b/runtime/ecsact_rt_entt_dynamic.cc index fff9489..6f919a6 100644 --- a/runtime/ecsact_rt_entt_dynamic.cc +++ b/runtime/ecsact_rt_entt_dynamic.cc @@ -6,12 +6,22 @@ * derived from the input Ecsact files they will not be defined here. */ +#include #include "ecsact/runtime/core.h" #include "ecsact/entt/detail/globals.hh" #include "ecsact/entt/registry_util.hh" #include "ecsact/entt/entity.hh" +#include "ecsact/entt/detail/assoc_fields_hash.hh" #include "ecsact/entt/detail/system_execution_context.hh" +#ifdef __clang__ +static_assert(true, "workaround https://github.com/clangd/clangd/issues/1167"); +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Winconsistent-dllimport" +#endif + +using ecsact::entt::detail::get_assoc_fields_hash; + bool ecsact_system_execution_context_same( const ecsact_system_execution_context* a, const ecsact_system_execution_context* b @@ -80,7 +90,14 @@ void ecsact_system_execution_context_remove( ... ) { assert(context != nullptr); - return context->remove(comp_id); + std::va_list indexed_fields; + va_start(indexed_fields, comp_id); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(comp_id), + indexed_fields + ); + va_end(indexed_fields); + return context->remove(comp_id, assoc_fields_hash); } void ecsact_system_execution_context_get( @@ -90,7 +107,14 @@ void ecsact_system_execution_context_get( ... ) { assert(context != nullptr); - return context->get(comp_id, out_component_data); + std::va_list indexed_fields; + va_start(indexed_fields, out_component_data); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(comp_id), + indexed_fields + ); + va_end(indexed_fields); + return context->get(comp_id, out_component_data, assoc_fields_hash); } void ecsact_system_execution_context_update( @@ -100,7 +124,14 @@ void ecsact_system_execution_context_update( ... ) { assert(context != nullptr); - return context->update(comp_id, component_data); + std::va_list indexed_fields; + va_start(indexed_fields, component_data); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(comp_id), + indexed_fields + ); + va_end(indexed_fields); + return context->update(comp_id, component_data, assoc_fields_hash); } bool ecsact_system_execution_context_has( @@ -109,7 +140,14 @@ bool ecsact_system_execution_context_has( ... ) { assert(context != nullptr); - return context->has(comp_id); + std::va_list indexed_fields; + va_start(indexed_fields, comp_id); + auto assoc_fields_hash = get_assoc_fields_hash( + ecsact_id_cast(comp_id), + indexed_fields + ); + va_end(indexed_fields); + return context->has(comp_id, assoc_fields_hash); } void ecsact_system_execution_context_action( @@ -126,3 +164,7 @@ const ecsact_system_execution_context* ecsact_system_execution_context_parent( assert(context != nullptr); return context->parent_ctx; } + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif From 7c1de44358dc729ecc398d5d3efb0ea257e563cc Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 27 Jun 2024 11:03:28 -0700 Subject: [PATCH 11/19] chore: working on assoc core api tests --- .editorconfig | 2 + ecsact/entt/detail/apply_pending.hh | 1 - ecsact/entt/detail/assoc_fields_hash.hh | 6 +- ecsact/entt/detail/codegen_error.hh | 7 +++ ecsact/entt/detail/indexed_storage.hh | 19 ++++++ ecsact/entt/error_check.hh | 14 ++--- ecsact/entt/execution.hh | 6 +- ecsact/entt/wrapper/core.hh | 58 ++++++++++++++----- ecsact/entt/wrapper/dynamic.hh | 11 +++- rt_entt_codegen/core/BUILD.bazel | 1 + rt_entt_codegen/core/assoc_fields_hash.cc | 54 ++++++++++++++++- rt_entt_codegen/core/core.hh | 5 ++ rt_entt_codegen/core/print_sys_exec.cc | 13 +++++ .../core/update_indexed_storage.cc | 47 +++++++++++++++ rt_entt_codegen/rt_entt_codegen.cc | 3 +- rt_entt_codegen/shared/ecsact_entt_details.cc | 25 ++++++++ rt_entt_codegen/shared/ecsact_entt_details.hh | 2 + test/assoc/BUILD.bazel | 36 ++++++++++++ test/assoc/assoc_test.cc | 42 ++++++++++++++ test/assoc/assoc_test.ecsact | 6 ++ test/spawn.cc | 1 + 21 files changed, 326 insertions(+), 33 deletions(-) create mode 100644 ecsact/entt/detail/codegen_error.hh create mode 100644 ecsact/entt/detail/indexed_storage.hh create mode 100644 rt_entt_codegen/core/update_indexed_storage.cc create mode 100644 test/assoc/BUILD.bazel create mode 100644 test/assoc/assoc_test.cc create mode 100644 test/assoc/assoc_test.ecsact diff --git a/.editorconfig b/.editorconfig index 0b3779e..8fb9453 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,3 +3,5 @@ root = true [*] end_of_line = lf insert_final_newline = true +indent_size = 4 + diff --git a/ecsact/entt/detail/apply_pending.hh b/ecsact/entt/detail/apply_pending.hh index b3cfe1d..6127385 100644 --- a/ecsact/entt/detail/apply_pending.hh +++ b/ecsact/entt/detail/apply_pending.hh @@ -21,7 +21,6 @@ auto apply_pending_add(ecsact::entt::registry_t& registry) -> void { registry .emplace>(entity, comp.value, false); add_system_markers_if_needed(registry, entity); - // lifecycle_on_add(registry, entity, comp.value); } ); } diff --git a/ecsact/entt/detail/assoc_fields_hash.hh b/ecsact/entt/detail/assoc_fields_hash.hh index ed8b6d1..9f733a5 100644 --- a/ecsact/entt/detail/assoc_fields_hash.hh +++ b/ecsact/entt/detail/assoc_fields_hash.hh @@ -9,4 +9,8 @@ auto get_assoc_fields_hash( ecsact_composite_id compo_id, std::va_list indexed_field_values ) -> std::uint64_t; -} + +template + requires(C::has_assoc_fields) +auto get_assoc_fields_hash(const C&) -> std::uint64_t; +} // namespace ecsact::entt::detail diff --git a/ecsact/entt/detail/codegen_error.hh b/ecsact/entt/detail/codegen_error.hh new file mode 100644 index 0000000..87a3f59 --- /dev/null +++ b/ecsact/entt/detail/codegen_error.hh @@ -0,0 +1,7 @@ +#pragma once + +namespace ecsact::entt::detail { +template +constexpr bool unimplemented_by_codegen = false; +} + diff --git a/ecsact/entt/detail/indexed_storage.hh b/ecsact/entt/detail/indexed_storage.hh new file mode 100644 index 0000000..48d21d5 --- /dev/null +++ b/ecsact/entt/detail/indexed_storage.hh @@ -0,0 +1,19 @@ +#pragma once + +#include "codegen_error.hh" +#include "ecsact/entt/detail/registry.hh" +#include "ecsact/entt/detail/codegen_error.hh" + +namespace ecsact::entt::detail { + +template +auto update_indexed_storage(ecsact::entt::registry_t& registry) -> void { + static_assert(detail::unimplemented_by_codegen, R"( + ----------------------------------------------------------------------------- +| (!) CODEGEN ERROR | +| `update_indexed_storage<>` template specialization cannot be found. This is | +| typically generated by ecsact_rt_entt_codegen. | + ----------------------------------------------------------------------------- +)"); +} +} // namespace ecsact::entt::detail diff --git a/ecsact/entt/error_check.hh b/ecsact/entt/error_check.hh index fff545d..9ec764e 100644 --- a/ecsact/entt/error_check.hh +++ b/ecsact/entt/error_check.hh @@ -5,15 +5,11 @@ #include #include #include +#include "detail/codegen_error.hh" #include "ecsact/runtime/common.h" #include "ecsact/runtime/core.h" #include "entt/entity/registry.hpp" -#include "ecsact/entt/entity.hh" - -namespace ecsact::entt::detail { -template -constexpr bool error_check_unimplemented_by_codegen = false; -} +#include "ecsact/entt/detail/codegen_error.hh" namespace ecsact::entt { @@ -23,7 +19,7 @@ auto check_add_component_error( // ::ecsact::entt::entity_id, const C& ) -> ecsact_add_error { - static_assert(detail::error_check_unimplemented_by_codegen, R"( + static_assert(detail::unimplemented_by_codegen, R"( ----------------------------------------------------------------------------- | (!) CODEGEN ERROR | | `check_add_component_error<>` template specialization cannot be found. This | @@ -38,7 +34,7 @@ auto check_update_component_error( // ::ecsact::entt::entity_id, const C& ) -> ecsact_update_error { - static_assert(detail::error_check_unimplemented_by_codegen, R"( + static_assert(detail::unimplemented_by_codegen, R"( ----------------------------------------------------------------------------- | (!) CODEGEN ERROR | | `check_update_component_error<>` template specialization cannot be found. | @@ -52,7 +48,7 @@ auto check_action_error( // ecsact::entt::registry_t&, const A& ) -> ecsact_execute_systems_error { - static_assert(detail::error_check_unimplemented_by_codegen, R"( + static_assert(detail::unimplemented_by_codegen, R"( ----------------------------------------------------------------------------- | (!) CODEGEN ERROR | | `check_action_error<>` template specialization cannot be found. | diff --git a/ecsact/entt/execution.hh b/ecsact/entt/execution.hh index f407d0e..8d25e81 100644 --- a/ecsact/entt/execution.hh +++ b/ecsact/entt/execution.hh @@ -8,11 +8,7 @@ #include "ecsact/entt/entity.hh" #include "entt/entity/registry.hpp" #include "ecsact/entt/detail/globals.hh" - -namespace ecsact::entt::detail { -template -constexpr bool unimplemented_by_codegen = false; -} +#include "ecsact/entt/detail/codegen_error.hh" namespace ecsact::entt { diff --git a/ecsact/entt/wrapper/core.hh b/ecsact/entt/wrapper/core.hh index 0b7614f..6dbeaa9 100644 --- a/ecsact/entt/wrapper/core.hh +++ b/ecsact/entt/wrapper/core.hh @@ -9,6 +9,7 @@ #include "ecsact/entt/registry_util.hh" #include "ecsact/entt/error_check.hh" #include "ecsact/entt/detail/execution_events_collector.hh" +#include "ecsact/entt/detail/assoc_fields_hash.hh" namespace ecsact::entt::wrapper::core { @@ -22,7 +23,13 @@ inline auto has_component( // auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; assert(C::id == component_id); - return reg.all_of(entity); + if constexpr(C::has_assoc_fields) { + auto storage = + reg.storage(static_cast<::entt::id_type>(assoc_fields_hash)); + return storage.contains(entity); + } else { + return reg.all_of(entity); + } } template @@ -35,9 +42,29 @@ inline auto get_component( auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; assert(C::id == component_id); +#ifndef NDEBUG + if(C::id != component_id) { + return nullptr; + } + if(!has_component( + registry_id, + entity_id, + component_id, + assoc_fields_hash + )) { + return nullptr; + } +#endif - const C& comp = reg.get(entity); - return ∁ + if constexpr(C::has_assoc_fields) { + const C& comp = + reg.storage(static_cast<::entt::id_type>(assoc_fields_hash)) + .get(entity); + return ∁ + } else { + const C& comp = reg.get(entity); + return ∁ + } } template @@ -60,13 +87,16 @@ inline auto add_component( // if(err == ECSACT_ADD_OK) { if constexpr(std::is_empty_v) { reg.emplace(entity); + } else if constexpr(C::has_assoc_fields) { + auto comp = static_cast(component_data); + auto assoc_fields_hash = + ecsact::entt::detail::get_assoc_fields_hash(*comp); + reg.storage(static_cast<::entt::id_type>(assoc_fields_hash)) + .emplace(entity, *comp); } else { - reg.emplace>( - entity, - *static_cast(component_data), - false - ); - reg.emplace(entity, *static_cast(component_data)); + auto comp = static_cast(component_data); + reg.emplace>(entity, *comp, false); + reg.emplace(entity, *comp); } ecsact::entt::detail::add_system_markers_if_needed(reg, entity); @@ -138,12 +168,12 @@ inline auto update_component( // return err; } - const auto& in_component = *static_cast(component_data); - auto& current_component = reg.template get(entity); - - current_component = in_component; + if constexpr(C::has_assoc_fields) { + } else { + reg.template get(entity) = *static_cast(component_data); + } - return err; + return ECSACT_UPDATE_OK; } using update_component_exec_options_sig_t = ecsact_update_error (*)( // diff --git a/ecsact/entt/wrapper/dynamic.hh b/ecsact/entt/wrapper/dynamic.hh index bb7a329..3f9a8db 100644 --- a/ecsact/entt/wrapper/dynamic.hh +++ b/ecsact/entt/wrapper/dynamic.hh @@ -22,6 +22,7 @@ auto context_add( using ecsact::entt::component_removed; using ecsact::entt::detail::beforeremove_storage; using ecsact::entt::detail::exec_beforechange_storage; + using ecsact::entt::detail::get_assoc_fields_hash; using ecsact::entt::detail::pending_add; assert(ecsact_id_cast(C::id) == component_id); @@ -31,6 +32,15 @@ auto context_add( if constexpr(std::is_empty_v) { registry.template emplace_or_replace>(entity); + } else if constexpr(C::has_assoc_fields) { + auto component = static_cast(component_data); + auto assoc_fields_hash = get_assoc_fields_hash(*component); + registry.template storage(assoc_fields_hash).emplace(entity, *component); + registry.template emplace>( + entity, + *component, + false + ); } else { const C* component = static_cast(component_data); registry.template emplace_or_replace>(entity, *component); @@ -130,7 +140,6 @@ auto context_get( std::uint64_t assoc_fields_hash ) -> void { auto entity = context->entity; - *static_cast(out_component_data) = view.template get(entity); } diff --git a/rt_entt_codegen/core/BUILD.bazel b/rt_entt_codegen/core/BUILD.bazel index a45dbb9..c9c4b87 100644 --- a/rt_entt_codegen/core/BUILD.bazel +++ b/rt_entt_codegen/core/BUILD.bazel @@ -12,6 +12,7 @@ cc_library( # keep sorted _CORE_CODEGEN_METHODS = { "assoc_fields_hash": [], + "update_indexed_storage": [], "execute_systems": [ "//rt_entt_codegen/shared:parallel", "//rt_entt_codegen/shared:system_variant", diff --git a/rt_entt_codegen/core/assoc_fields_hash.cc b/rt_entt_codegen/core/assoc_fields_hash.cc index a48332d..07b56eb 100644 --- a/rt_entt_codegen/core/assoc_fields_hash.cc +++ b/rt_entt_codegen/core/assoc_fields_hash.cc @@ -7,6 +7,7 @@ #include "ecsact/lang-support/lang-cc.hh" #include "ecsact/cpp_codegen_plugin_util.hh" +using ecsact::codegen_plugin_context; using ecsact::cc_lang_support::c_identifier; using ecsact::cc_lang_support::cpp_field_type_name; using ecsact::cc_lang_support::cpp_identifier; @@ -15,6 +16,7 @@ using ecsact::cpp_codegen_plugin_util::comma_delim; using ecsact::cpp_codegen_plugin_util::method_printer; using ecsact::meta::decl_full_name; using ecsact::meta::system_assoc_ids; +using ecsact::rt_entt_codegen::ecsact_entt_details; template static auto get_assoc_fields(CompositeID compo_id @@ -36,7 +38,7 @@ static auto get_assoc_fields(CompositeID compo_id return result; } -auto ecsact::rt_entt_codegen::core::print_assoc_fields_hash( +auto print_assoc_fields_hash_va_list( codegen_plugin_context& ctx, const ecsact_entt_details& details ) -> void { @@ -90,3 +92,53 @@ auto ecsact::rt_entt_codegen::core::print_assoc_fields_hash( ctx.write("return 0;"); } + +auto print_assoc_fields_hash_spec( + codegen_plugin_context& ctx, + const ecsact_entt_details& details, + ecsact_component_id comp_id +) -> void { + auto assoc_fields = get_assoc_fields(comp_id); + if(assoc_fields.empty()) { + return; + } + + auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_id)); + ctx.write("template<> "); + auto printer = // + method_printer{ + ctx, + std::format( + "ecsact::entt::detail::get_assoc_fields_hash<{}>", + comp_cpp_ident + ) + } // + .parameter(std::format("const {}&", comp_cpp_ident), "comp") + .return_type("std::uint64_t"); + + ctx.write(std::format( + "return " + "::ecsact::entt::detail::hash_vals(static_cast({}::id), " + "{});", + comp_cpp_ident, + comma_delim(std::views::transform( + assoc_fields, + [&](auto field_id) -> std::string { + return std::format( + "comp.{}", + ecsact::meta::field_name(comp_id, field_id) + ); + } + )) + )); +} + +auto ecsact::rt_entt_codegen::core::print_assoc_fields_hash( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void { + print_assoc_fields_hash_va_list(ctx, details); + for(auto comp_id : details.all_components) { + print_assoc_fields_hash_spec(ctx, details, comp_id); + } +} diff --git a/rt_entt_codegen/core/core.hh b/rt_entt_codegen/core/core.hh index 537f3b5..716a93a 100644 --- a/rt_entt_codegen/core/core.hh +++ b/rt_entt_codegen/core/core.hh @@ -6,6 +6,11 @@ namespace ecsact::rt_entt_codegen::core { +auto print_update_indexed_storage( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void; + auto print_assoc_fields_hash( codegen_plugin_context& ctx, const ecsact_entt_details& details diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index 6f6dfd2..ca3e6fd 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -460,6 +460,19 @@ static auto print_execute_systems( } } + ctx.write( + "// TODO: Optimize this by only going over components that can have " + "indexed storage\n" + ); + for(auto comp_id : sys_details.get_all_writable_comps()) { + auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_id)); + ctx.write(std::format( + "::ecsact::entt::detail::update_indexed_storage<{}>({});\n", + comp_cpp_ident, + names.registry_var_name + )); + } + for(const auto& provider : system_providers) { provider->post_iteration(ctx, names); } diff --git a/rt_entt_codegen/core/update_indexed_storage.cc b/rt_entt_codegen/core/update_indexed_storage.cc new file mode 100644 index 0000000..bd77745 --- /dev/null +++ b/rt_entt_codegen/core/update_indexed_storage.cc @@ -0,0 +1,47 @@ + +#include "core.hh" + +#include +#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" + +using ecsact::codegen_plugin_context; +using ecsact::cc_lang_support::cpp_identifier; +using ecsact::cpp_codegen_plugin_util::method_printer; +using ecsact::meta::decl_full_name; +using ecsact::rt_entt_codegen::ecsact_entt_details; + +static auto print_update_indexed_storage_component( + codegen_plugin_context& ctx, + const ecsact_entt_details& details, + ecsact_component_like_id comp_like_id +) -> void { + auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_like_id)); + + ctx.write("template<> "); + auto printer = + method_printer{ + ctx, + std::format( + "ecsact::entt::detail::update_indexed_storage<{}>", + comp_cpp_ident + ) + } + .parameter("ecsact::entt::registry_t&", "reg") + .return_type("void"); +} + +auto ecsact::rt_entt_codegen::core::print_update_indexed_storage( + codegen_plugin_context& ctx, + const ecsact_entt_details& details +) -> void { + for(auto comp_id : details.all_components) { + print_update_indexed_storage_component( + ctx, + details, + ecsact_id_cast(comp_id) + ); + } +} diff --git a/rt_entt_codegen/rt_entt_codegen.cc b/rt_entt_codegen/rt_entt_codegen.cc index 9076495..83f7b4d 100644 --- a/rt_entt_codegen/rt_entt_codegen.cc +++ b/rt_entt_codegen/rt_entt_codegen.cc @@ -55,7 +55,7 @@ void ecsact_codegen_plugin( inc_header(ctx, "ecsact/entt/detail/registry.hh"); inc_header(ctx, "ecsact/entt/detail/bytes.hh"); inc_header(ctx, "ecsact/entt/detail/hash.hh"); - inc_header(ctx, "ecsact/entt/detail/hash.hh"); + inc_header(ctx, "ecsact/entt/detail/indexed_storage.hh"); inc_header(ctx, "ecsact/entt/wrapper/core.hh"); inc_header(ctx, "ecsact/entt/wrapper/dynamic.hh"); inc_header(ctx, "ecsact/entt/error_check.hh"); @@ -237,6 +237,7 @@ void ecsact_codegen_plugin( core::print_assoc_fields_hash(ctx, details); core::print_assoc_globals(ctx, details); + core::print_update_indexed_storage(ctx, details); core::print_entity_match_fn(ctx, details); core::print_system_marker_add_fn(ctx, details); core::print_system_marker_remove_fn(ctx, details); diff --git a/rt_entt_codegen/shared/ecsact_entt_details.cc b/rt_entt_codegen/shared/ecsact_entt_details.cc index c18c7ae..bc76c2d 100644 --- a/rt_entt_codegen/shared/ecsact_entt_details.cc +++ b/rt_entt_codegen/shared/ecsact_entt_details.cc @@ -1,6 +1,7 @@ #include "ecsact_entt_details.hh" #include +#include #include "ecsact/codegen/plugin.h" #include "ecsact/codegen/plugin.hh" #include "ecsact/lang-support/lang-cc.hh" @@ -80,6 +81,30 @@ static auto collect_all_actions( // } } +auto ecsact_entt_system_details::get_all_writable_comps() const + -> std::vector { + auto comp_ids = std::vector{ + writable_comps.begin(), + writable_comps.end(), + }; + + for(auto assoc_details : association_details) { + for(auto&& [comp_id, caps] : assoc_details.capabilities) { + if((caps & ECSACT_SYS_CAP_WRITEONLY) != ECSACT_SYS_CAP_WRITEONLY) { + continue; + } + + if(std::ranges::find(comp_ids, comp_id) != comp_ids.end()) { + continue; + } + + comp_ids.emplace_back(comp_id); + } + } + + return comp_ids; +} + auto ecsact_entt_system_details::fill_system_details( ecsact_entt_system_details& out_details, const std::unordered_map& diff --git a/rt_entt_codegen/shared/ecsact_entt_details.hh b/rt_entt_codegen/shared/ecsact_entt_details.hh index 7990946..9069e37 100644 --- a/rt_entt_codegen/shared/ecsact_entt_details.hh +++ b/rt_entt_codegen/shared/ecsact_entt_details.hh @@ -52,6 +52,8 @@ struct ecsact_entt_system_details { * requirements*/ generate_t generate_comps; + auto get_all_writable_comps() const -> std::vector; + static auto from_system_like( // ecsact_system_like_id sys_like_id ) -> ecsact_entt_system_details; diff --git a/test/assoc/BUILD.bazel b/test/assoc/BUILD.bazel new file mode 100644 index 0000000..1f3d83b --- /dev/null +++ b/test/assoc/BUILD.bazel @@ -0,0 +1,36 @@ +load("@ecsact_rt_entt//bazel:copts.bzl", "copts") +load("@ecsact_rt_entt//runtime:index.bzl", "ecsact_entt_runtime") +load("@rules_cc//cc:defs.bzl", "cc_test") +load("@rules_ecsact//ecsact:defs.bzl", "ecsact_codegen") + +ecsact_codegen( + name = "ecsact_cc_system_impl_srcs", + srcs = ["assoc_test.ecsact"], + output_directory = "generated", + plugins = [ + "@ecsact_lang_cpp//cpp_systems_source_codegen", + ], +) + +ecsact_entt_runtime( + name = "runtime", + srcs = ["assoc_test.ecsact"], + ECSACT_ENTT_RUNTIME_PACKAGE = "::assoc_test::package", + ECSACT_ENTT_RUNTIME_USER_HEADER = "assoc_test.ecsact.meta.hh", + system_impls = ["dynamic"], +) + +cc_test( + name = "test", + srcs = [ + "assoc_test.cc", + ":ecsact_cc_system_impl_srcs", + ], + args = ["--gtest_catch_exceptions=0"], + copts = copts, + deps = [ + ":runtime", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) diff --git a/test/assoc/assoc_test.cc b/test/assoc/assoc_test.cc new file mode 100644 index 0000000..90520d7 --- /dev/null +++ b/test/assoc/assoc_test.cc @@ -0,0 +1,42 @@ +#include "gtest/gtest.h" + +#include "ecsact/runtime/core.hh" +#include "ecsact/runtime/dynamic.h" + +#include "assoc_test.ecsact.hh" +#include "assoc_test.ecsact.systems.hh" + +using namespace assoc_test; + +TEST(AssocCore, EntityAssoc) { + auto reg = ecsact::core::registry{"EntityAssoc"}; + auto entity1 = reg.create_entity(); + auto entity2 = reg.create_entity(); + + ASSERT_FALSE(reg.has_component(entity1, entity2)); + ASSERT_FALSE(reg.has_component(entity1, entity1)); + + reg.add_component(entity1, EntityAssoc{entity2, 10}); + ASSERT_TRUE(reg.has_component(entity1, entity2)); + EXPECT_FALSE(reg.has_component(entity1, entity1)); + ASSERT_EQ(reg.get_component(entity1, entity1).n, 10); + + reg.update_component(entity1, EntityAssoc{entity1, 12}, entity2); + ASSERT_TRUE(reg.has_component(entity1, entity1)); + ASSERT_FALSE(reg.has_component(entity1, entity2)); + + reg.add_component(entity1, EntityAssoc{entity2, 18}); + ASSERT_TRUE(reg.has_component(entity1, entity1)); + ASSERT_TRUE(reg.has_component(entity1, entity2)); + ASSERT_EQ(reg.get_component(entity1, entity1).n, 12); + ASSERT_EQ(reg.get_component(entity1, entity2).n, 18); + + reg.remove_component(entity1, entity2); + ASSERT_FALSE(reg.has_component(entity1, entity2)); + ASSERT_TRUE(reg.has_component(entity1, entity1)); + ASSERT_EQ(reg.get_component(entity1, entity1).n, 12); + + reg.remove_component(entity1, entity2); + ASSERT_FALSE(reg.has_component(entity1, entity2)); + ASSERT_FALSE(reg.has_component(entity1, entity1)); +} diff --git a/test/assoc/assoc_test.ecsact b/test/assoc/assoc_test.ecsact new file mode 100644 index 0000000..5a0b007 --- /dev/null +++ b/test/assoc/assoc_test.ecsact @@ -0,0 +1,6 @@ +main package assoc_test; + +component EntityAssoc { entity e; i32 n; } +component Unique { i32 my_id; } +component FieldAssoc { Unique.my_id unique_id; i32 num; } + diff --git a/test/spawn.cc b/test/spawn.cc index be435f1..6f2703b 100644 --- a/test/spawn.cc +++ b/test/spawn.cc @@ -1,6 +1,7 @@ #include "spawn.hh" #include +#include namespace bp = boost::process; From 21578e9b23a87cec0e511c2b1c31ce0e329fd791 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 27 Jun 2024 11:05:54 -0700 Subject: [PATCH 12/19] chore: git overrides for easy sharing --- MODULE.bazel | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index c090911..1a9b5c5 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -15,14 +15,26 @@ bazel_dep(name = "ecsact_codegen", version = "0.2.0") bazel_dep(name = "ecsact_cli", version = "0.3.11") bazel_dep(name = "xxhash", version = "0.8.2") -local_path_override( - module_name = "ecsact_lang_cpp", - path = "../ecsact_lang_cpp", +# local_path_override( +# module_name = "ecsact_lang_cpp", +# path = "../ecsact_lang_cpp", +# ) + +git_override( + module_name = "ecsact_lang_cpp", + remote = "git@github.com:ecsact-dev/ecsact_lang_cpp.git", + commit = "1add2a6144776659b4f69f3b4132eefb0cb07a50", ) -local_path_override( - module_name = "ecsact_runtime", - path = "../ecsact_runtime", +# local_path_override( +# module_name = "ecsact_runtime", +# path = "../ecsact_runtime", +# ) + +git_override( + module_name = "ecsact_runtime", + remote = "git@github.com:ecsact-dev/ecsact_runtime.git", + commit = "bb28aff1a1fbf214a0740f94ffddc35bf3f09043", ) bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True) From c4b11605981893cb754481665390e93605aa40bd Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 27 Jun 2024 11:10:32 -0700 Subject: [PATCH 13/19] chore: making sure recipe test is passing --- build_recipe.yml | 6 ++++++ ecsact/entt/wrapper/core.hh | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/build_recipe.yml b/build_recipe.yml index be98340..a80214e 100644 --- a/build_recipe.yml +++ b/build_recipe.yml @@ -189,6 +189,12 @@ sources: outdir: include/ecsact/entt/detail - path: ./ecsact/entt/detail/hash.hh outdir: include/ecsact/entt/detail + - path: ./ecsact/entt/detail/assoc_fields_hash.hh + outdir: include/ecsact/entt/detail + - path: ./ecsact/entt/detail/codegen_error.hh + outdir: include/ecsact/entt/detail + - path: ./ecsact/entt/detail/indexed_storage.hh + outdir: include/ecsact/entt/detail # ecsact/entt/wrapper - path: ./ecsact/entt/wrapper/core.hh outdir: include/ecsact/entt/wrapper diff --git a/ecsact/entt/wrapper/core.hh b/ecsact/entt/wrapper/core.hh index 6dbeaa9..3e6b179 100644 --- a/ecsact/entt/wrapper/core.hh +++ b/ecsact/entt/wrapper/core.hh @@ -24,9 +24,8 @@ inline auto has_component( // auto entity = ecsact::entt::entity_id{entity_id}; assert(C::id == component_id); if constexpr(C::has_assoc_fields) { - auto storage = - reg.storage(static_cast<::entt::id_type>(assoc_fields_hash)); - return storage.contains(entity); + return reg.storage(static_cast<::entt::id_type>(assoc_fields_hash)) + .contains(entity); } else { return reg.all_of(entity); } From 00501e7a9141ffbde3f1a496d12653466eeac43c Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 27 Jun 2024 13:09:24 -0700 Subject: [PATCH 14/19] feat: first assoc core api test passing --- ecsact/entt/detail/assoc_fields_hash.hh | 12 +- ecsact/entt/detail/globals.hh | 34 +++--- ecsact/entt/detail/hash.hh | 17 ++- .../entt/detail/system_execution_context.hh | 21 ++-- ecsact/entt/entity.hh | 5 + ecsact/entt/wrapper/core.hh | 113 ++++++++++-------- ecsact/entt/wrapper/dynamic.hh | 9 +- rt_entt_codegen/core/assoc_fields_hash.cc | 8 +- rt_entt_codegen/core/execution_options.cc | 10 +- rt_entt_codegen/core/print_sys_exec.cc | 20 +++- rt_entt_codegen/core/sorting_components.cc | 2 +- .../association/association.cc | 22 +++- .../system_provider/system_ctx_functions.cc | 6 +- rt_entt_codegen/rt_entt_codegen.cc | 7 ++ rt_entt_codegen/shared/util.cc | 2 +- runtime/hash.cc | 24 +++- test/assoc/assoc_test.cc | 51 ++++++-- 17 files changed, 250 insertions(+), 113 deletions(-) diff --git a/ecsact/entt/detail/assoc_fields_hash.hh b/ecsact/entt/detail/assoc_fields_hash.hh index 9f733a5..0ec174a 100644 --- a/ecsact/entt/detail/assoc_fields_hash.hh +++ b/ecsact/entt/detail/assoc_fields_hash.hh @@ -2,15 +2,23 @@ #include #include +#include "entt/entt.hpp" #include "ecsact/runtime/common.h" namespace ecsact::entt::detail { +using assoc_hash_value_t = std::uint32_t; +static_assert( + sizeof(::entt::id_type) == sizeof(assoc_hash_value_t), + "EnTT storage id type must match the size of ecsact_rt_entt internal hash " + "algorithm size" +); + auto get_assoc_fields_hash( ecsact_composite_id compo_id, std::va_list indexed_field_values -) -> std::uint64_t; +) -> assoc_hash_value_t; template requires(C::has_assoc_fields) -auto get_assoc_fields_hash(const C&) -> std::uint64_t; +auto get_assoc_fields_hash(const C&) -> assoc_hash_value_t; } // namespace ecsact::entt::detail diff --git a/ecsact/entt/detail/globals.hh b/ecsact/entt/detail/globals.hh index 6ff2e5b..7138ad0 100644 --- a/ecsact/entt/detail/globals.hh +++ b/ecsact/entt/detail/globals.hh @@ -59,10 +59,10 @@ extern const std::unordered_map< // add_component_fns; using get_component_fn_sig_t = const void* (*)( // - ecsact_registry_id reg_id, - ecsact_entity_id entity_id, - ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ); /** @@ -76,11 +76,11 @@ extern const std::unordered_map< // get_component_fns; using update_component_fn_sig_t = ecsact_update_error (*)( - ecsact_registry_id reg_id, - ecsact_entity_id entity_id, - ecsact_component_id component_id, - const void* component_data, - std::uint64_t assoc_fields_hash + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + const void* component_data, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ); /** @@ -94,10 +94,10 @@ extern const std::unordered_map< // update_component_fns; using remove_component_fn_sig_t = void (*)( - ecsact_registry_id reg_id, - ecsact_entity_id entity_id, - ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ); /** @@ -111,10 +111,10 @@ extern const std::unordered_map< // remove_component_fns; using has_component_fn_sig_t = bool (*)( - ecsact_registry_id reg_id, - ecsact_entity_id entity_id, - ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id reg_id, + ecsact_entity_id entity_id, + ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ); /** diff --git a/ecsact/entt/detail/hash.hh b/ecsact/entt/detail/hash.hh index 0093a4b..8b79cba 100644 --- a/ecsact/entt/detail/hash.hh +++ b/ecsact/entt/detail/hash.hh @@ -12,14 +12,25 @@ namespace ecsact::entt::detail { * @param data_length length of @p data * @returns hash value */ -auto bytes_hash( // +auto bytes_hash32( // + std::byte* data, + int data_length +) -> std::uint32_t; + +auto bytes_hash64( // std::byte* data, int data_length ) -> std::uint64_t; template -auto hash_vals(Args&&... args) -> std::uint64_t { +auto hash_vals32(Args&&... args) -> std::uint32_t { + auto bytes = bytes_copy(args...); + return bytes_hash32(bytes.data(), bytes.size()); +} + +template +auto hash_vals64(Args&&... args) -> std::uint64_t { auto bytes = bytes_copy(args...); - return bytes_hash(bytes.data(), bytes.size()); + return bytes_hash64(bytes.data(), bytes.size()); } } // namespace ecsact::entt::detail diff --git a/ecsact/entt/detail/system_execution_context.hh b/ecsact/entt/detail/system_execution_context.hh index 9d53593..93b58c1 100644 --- a/ecsact/entt/detail/system_execution_context.hh +++ b/ecsact/entt/detail/system_execution_context.hh @@ -11,6 +11,7 @@ #include "ecsact/entt/event_markers.hh" #include "ecsact/entt/entity.hh" #include "ecsact/entt/detail/registry.hh" +#include "ecsact/entt/detail/assoc_fields_hash.hh" namespace ecsact::entt { /** @@ -55,25 +56,25 @@ struct ecsact_system_execution_context { ) -> void = 0; virtual auto remove( // - ecsact_component_like_id component_id, - std::uint64_t assoc_fields_hash + ecsact_component_like_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void = 0; virtual auto get( // - ecsact_component_like_id component_id, - void* out_component_data, - std::uint64_t assoc_fields_hash + ecsact_component_like_id component_id, + void* out_component_data, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void = 0; virtual auto update( // - ecsact_component_like_id component_id, - const void* component_data, - std::uint64_t assoc_fields_hash + ecsact_component_like_id component_id, + const void* component_data, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void = 0; virtual auto has( // - ecsact_component_like_id component_id, - std::uint64_t assoc_fields_hash + ecsact_component_like_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> bool = 0; virtual auto generate( // diff --git a/ecsact/entt/entity.hh b/ecsact/entt/entity.hh index b5e80cf..947d6b8 100644 --- a/ecsact/entt/entity.hh +++ b/ecsact/entt/entity.hh @@ -13,6 +13,11 @@ namespace ecsact::entt { class entity_id { std::int32_t _id; + static_assert( + sizeof(::entt::entity) == sizeof(ecsact_entity_id), + "Ecsact entity ID must be same size as EnTT entity ID" + ); + public: inline entity_id() { } diff --git a/ecsact/entt/wrapper/core.hh b/ecsact/entt/wrapper/core.hh index 3e6b179..5754e33 100644 --- a/ecsact/entt/wrapper/core.hh +++ b/ecsact/entt/wrapper/core.hh @@ -15,28 +15,28 @@ namespace ecsact::entt::wrapper::core { template inline auto has_component( // - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> bool { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; assert(C::id == component_id); if constexpr(C::has_assoc_fields) { - return reg.storage(static_cast<::entt::id_type>(assoc_fields_hash)) - .contains(entity); + auto storage_id = static_cast<::entt::id_type>(assoc_fields_hash); + return reg.storage(storage_id).contains(entity); } else { - return reg.all_of(entity); + return reg.storage().contains(entity); } } template inline auto get_component( - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> const void* { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; @@ -90,8 +90,8 @@ inline auto add_component( // auto comp = static_cast(component_data); auto assoc_fields_hash = ecsact::entt::detail::get_assoc_fields_hash(*comp); - reg.storage(static_cast<::entt::id_type>(assoc_fields_hash)) - .emplace(entity, *comp); + auto storage_id = static_cast<::entt::id_type>(assoc_fields_hash); + reg.storage(storage_id).emplace(entity, *comp); } else { auto comp = static_cast(component_data); reg.emplace>(entity, *comp, false); @@ -144,11 +144,11 @@ inline auto add_component_exec_options( // template inline auto update_component( // - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - const void* component_data, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + const void* component_data, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> ecsact_update_error { using ecsact::entt::detail::exec_beforechange_storage; @@ -167,29 +167,43 @@ inline auto update_component( // return err; } + auto new_comp = static_cast(component_data); + if constexpr(C::has_assoc_fields) { + auto new_assoc_fields_hash = + ecsact::entt::detail::get_assoc_fields_hash(*new_comp); + + if(new_assoc_fields_hash == assoc_fields_hash) { + auto storage_id = static_cast<::entt::id_type>(assoc_fields_hash); + reg.template storage(storage_id).get(entity) = *new_comp; + } else { + auto new_storage_id = static_cast<::entt::id_type>(new_assoc_fields_hash); + auto old_storage_id = static_cast<::entt::id_type>(assoc_fields_hash); + reg.template storage(old_storage_id).erase(entity); + reg.template storage(new_storage_id).emplace(entity, *new_comp); + } } else { - reg.template get(entity) = *static_cast(component_data); + reg.template get(entity) = *new_comp; } return ECSACT_UPDATE_OK; } using update_component_exec_options_sig_t = ecsact_update_error (*)( // - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - const void* component_data, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + const void* component_data, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ); template inline auto update_component_exec_options( // - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - const void* component_data, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + const void* component_data, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> ecsact_update_error { using ecsact::entt::detail::exec_beforechange_storage; @@ -227,37 +241,42 @@ static_assert(std::is_same_v< template auto remove_component( - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void { auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; assert(C::id == component_id); - reg.remove(entity); - if constexpr(!std::is_empty_v) { - reg.remove>(entity); + if constexpr(C::has_assoc_fields) { + auto storage_id = static_cast<::entt::id_type>(assoc_fields_hash); + reg.storage(storage_id).erase(entity); + } else { + reg.remove(entity); + if constexpr(!std::is_empty_v) { + reg.remove>(entity); + } + reg.template remove>(entity); + reg.template emplace_or_replace>(entity); + ecsact::entt::detail::remove_system_markers_if_needed(reg, entity); } - reg.template remove>(entity); - reg.template emplace_or_replace>(entity); - ecsact::entt::detail::remove_system_markers_if_needed(reg, entity); } using remove_component_exec_options_sig_t = void (*)( // - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ); template auto remove_component_exec_options( - ecsact_registry_id registry_id, - ecsact_entity_id entity_id, - [[maybe_unused]] ecsact_component_id component_id, - std::uint64_t assoc_fields_hash + ecsact_registry_id registry_id, + ecsact_entity_id entity_id, + [[maybe_unused]] ecsact_component_id component_id, + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void { using ecsact::entt::detail::pending_remove; diff --git a/ecsact/entt/wrapper/dynamic.hh b/ecsact/entt/wrapper/dynamic.hh index 3f9a8db..5f45aaf 100644 --- a/ecsact/entt/wrapper/dynamic.hh +++ b/ecsact/entt/wrapper/dynamic.hh @@ -9,6 +9,7 @@ #include "ecsact/entt/detail/internal_markers.hh" #include "ecsact/entt/event_markers.hh" #include "ecsact/entt/detail/system_execution_context.hh" +#include "ecsact/entt/detail/assoc_fields_hash.hh" namespace ecsact::entt::wrapper::dynamic { @@ -81,7 +82,7 @@ auto context_remove( ecsact_system_execution_context* context, [[maybe_unused]] ecsact_component_like_id component_id, auto& view, - std::uint64_t assoc_fields_hash + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void { assert(ecsact_id_cast(C::id) == component_id); @@ -137,7 +138,7 @@ auto context_get( [[maybe_unused]] ecsact_component_like_id component_id, void* out_component_data, auto& view, - std::uint64_t assoc_fields_hash + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void { auto entity = context->entity; *static_cast(out_component_data) = view.template get(entity); @@ -149,7 +150,7 @@ auto context_update( [[maybe_unused]] ecsact_component_like_id component_id, const void* in_component_data, auto& view, - std::uint64_t assoc_fields_hash + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> void { using ecsact::entt::detail::exec_beforechange_storage; // TODO(Kelwan): for remove, beforeremove_storage @@ -171,7 +172,7 @@ template auto context_has( ecsact_system_execution_context* context, [[maybe_unused]] ecsact_component_like_id component_id, - std::uint64_t assoc_fields_hash + ecsact::entt::detail::assoc_hash_value_t assoc_fields_hash ) -> bool { auto entity = context->entity; auto& registry = *context->registry; diff --git a/rt_entt_codegen/core/assoc_fields_hash.cc b/rt_entt_codegen/core/assoc_fields_hash.cc index 07b56eb..7168a50 100644 --- a/rt_entt_codegen/core/assoc_fields_hash.cc +++ b/rt_entt_codegen/core/assoc_fields_hash.cc @@ -46,7 +46,7 @@ auto print_assoc_fields_hash_va_list( method_printer{ctx, "ecsact::entt::detail::get_assoc_fields_hash"} // .parameter("ecsact_composite_id", "compo_id") .parameter("std::va_list", "indexed_field_values") - .return_type("std::uint64_t"); + .return_type("ecsact::entt::detail::assoc_hash_value_t"); for(auto comp_id : details.all_components) { auto compo_cpp_identifier = cpp_identifier(decl_full_name(comp_id)); @@ -75,7 +75,7 @@ auto print_assoc_fields_hash_va_list( ctx.write(std::format( "return " - "::ecsact::entt::detail::hash_vals(static_cast({}::id), " + "::ecsact::entt::detail::hash_vals32(static_cast({}::id), " "{});", compo_cpp_identifier, comma_delim(std::views::transform( @@ -114,11 +114,11 @@ auto print_assoc_fields_hash_spec( ) } // .parameter(std::format("const {}&", comp_cpp_ident), "comp") - .return_type("std::uint64_t"); + .return_type("ecsact::entt::detail::assoc_hash_value_t"); ctx.write(std::format( "return " - "::ecsact::entt::detail::hash_vals(static_cast({}::id), " + "::ecsact::entt::detail::hash_vals32(static_cast({}::id), " "{});", comp_cpp_ident, comma_delim(std::views::transform( diff --git a/rt_entt_codegen/core/execution_options.cc b/rt_entt_codegen/core/execution_options.cc index 17a53b6..3069c64 100644 --- a/rt_entt_codegen/core/execution_options.cc +++ b/rt_entt_codegen/core/execution_options.cc @@ -180,7 +180,10 @@ auto ecsact::rt_entt_codegen::core::print_execution_options( block(ctx, "for(int i = 0; i < options.update_components_length; i++)", [&] { ctx.write("auto& component = options.update_components[i];\n"); ctx.write("auto entity = options.update_components_entities[i];\n"); - ctx.write("auto assoc_fields_hash = std::uint64_t{}; // TODO\n\n"); + ctx.write( + "auto assoc_fields_hash = ecsact::entt::detail::assoc_hash_value_t{}; // " + "TODO\n\n" + ); ctx.write( "execution_update_fns.at(ecsact_id_cast(" @@ -193,7 +196,10 @@ auto ecsact::rt_entt_codegen::core::print_execution_options( block(ctx, "for(int i = 0; i < options.remove_components_length; i++)", [&] { ctx.write("auto& component_id = options.remove_components[i];\n"); ctx.write("auto entity = options.remove_components_entities[i];\n\n"); - ctx.write("auto assoc_fields_hash = std::uint64_t{}; // TODO\n\n"); + ctx.write( + "auto assoc_fields_hash = ecsact::entt::detail::assoc_hash_value_t{}; // " + "TODO\n\n" + ); ctx.write( "execution_remove_fns.at(ecsact_id_cast(" diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index ca3e6fd..ebd9bdf 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -100,7 +100,10 @@ static auto print_sys_exec_ctx_remove( auto printer = // method_printer{ctx, "remove"} .parameter("ecsact_component_like_id", "component_id") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("void final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { @@ -122,7 +125,10 @@ static auto print_sys_exec_ctx_get( method_printer{ctx, "get"} .parameter("ecsact_component_like_id", "component_id") .parameter("void*", "out_component_data") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("void final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { @@ -144,7 +150,10 @@ static auto print_sys_exec_ctx_update( method_printer{ctx, "update"} .parameter("ecsact_component_like_id", "component_id") .parameter("const void*", "component_data") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("void final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { @@ -165,7 +174,10 @@ static auto print_sys_exec_ctx_has( auto printer = // method_printer{ctx, "has"} .parameter("ecsact_component_like_id", "component_id") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("bool final"); auto result = std::ranges::find_if(system_providers, [&](auto provider) { diff --git a/rt_entt_codegen/core/sorting_components.cc b/rt_entt_codegen/core/sorting_components.cc index 3cba878..4c5f417 100644 --- a/rt_entt_codegen/core/sorting_components.cc +++ b/rt_entt_codegen/core/sorting_components.cc @@ -101,7 +101,7 @@ static auto print_system_entity_sorting_component_struct( ctx.write("\n);\n"); ctx.write( - "sorted.hash = ::ecsact::entt::detail::bytes_hash(bytes.data(), " + "sorted.hash = ::ecsact::entt::detail::bytes_hash64(bytes.data(), " "bytes.size());" ); }); diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index 3cdffdd..84e0789 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -139,7 +139,7 @@ auto provider::association::entity_iteration( ctx.write(std::format( "{0}.storage({3}.storage<{1}>(static_cast<::entt::id_type>(::ecsact::" "entt::detail::" - "hash_vals({1}::" + "hash_vals32({1}::" "id, {2}))));\n", assoc_view_names.at(assoc_id), compo_cpp_ident, @@ -318,7 +318,10 @@ auto provider::association::print_other_ctx_remove( auto printer = // method_printer{ctx, "remove"} .parameter("ecsact_component_like_id", "component_id") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("void final"); context_remove_impl(ctx, other_caps, details, view_type_name); @@ -333,7 +336,10 @@ auto provider::association::print_other_ctx_get( method_printer{ctx, "get"} .parameter("ecsact_component_like_id", "component_id") .parameter("void*", "out_component_data") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("void final"); context_get_impl(ctx, sys_like_id, details, view_type_name); @@ -348,7 +354,10 @@ auto provider::association::print_other_ctx_update( method_printer{ctx, "update"} .parameter("ecsact_component_like_id", "component_id") .parameter("const void*", "component_data") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("void final"); context_update_impl(ctx, sys_like_id, details, view_type_name); @@ -361,7 +370,10 @@ auto provider::association::print_other_ctx_has( auto printer = // method_printer{ctx, "has"} .parameter("ecsact_component_like_id", "component_id") - .parameter("std::uint64_t", "assoc_fields_hash") + .parameter( + "ecsact::entt::detail::assoc_hash_value_t", + "assoc_fields_hash" + ) .return_type("bool final"); context_has_impl(ctx, sys_like_id, details); diff --git a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc index 35433fa..c655b34 100644 --- a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc +++ b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc @@ -196,7 +196,8 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl( ctx.write(std::format( "using get_fn_t = void (*)(ecsact_system_execution_context*, " - "ecsact_component_like_id, void *, {}_t&, std::uint64_t);\n", + "ecsact_component_like_id, void *, {}_t&, " + "ecsact::entt::detail::assoc_hash_value_t);\n", view_type_name )); @@ -254,7 +255,8 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl( ctx.write(std::format( "using update_fn_t = void (*)(ecsact_system_execution_context*, " - "ecsact_component_like_id, const void *, {}_t&, std::uint64_t);\n", + "ecsact_component_like_id, const void *, {}_t&, " + "ecsact::entt::detail::assoc_hash_value_t);\n", view_type_name )); diff --git a/rt_entt_codegen/rt_entt_codegen.cc b/rt_entt_codegen/rt_entt_codegen.cc index 83f7b4d..7dac966 100644 --- a/rt_entt_codegen/rt_entt_codegen.cc +++ b/rt_entt_codegen/rt_entt_codegen.cc @@ -75,6 +75,13 @@ void ecsact_codegen_plugin( "ecsact::entt::actions_map&>;\n\n" ); + ctx.write( + "static_assert(sizeof(::entt::id_type) == " + "sizeof(ecsact::entt::detail::assoc_hash_value_t),\"EnTT " + "storage id type must match the size of ecsact_rt_entt internal hash " + "algorithm size\");\n\n" + ); + init_global(ctx, "registries"); init_global(ctx, "last_registry_id"); init_global(ctx, "system_impls"); diff --git a/rt_entt_codegen/shared/util.cc b/rt_entt_codegen/shared/util.cc index 35b2188..831a654 100644 --- a/rt_entt_codegen/shared/util.cc +++ b/rt_entt_codegen/shared/util.cc @@ -79,7 +79,7 @@ auto ecsact::rt_entt_codegen::util::make_view( // for(auto&& [compo_id, fields] : indexed_fields) { auto compo_name = cpp_identifier(decl_full_name(compo_id)); auto hash_fields_str = std::format( - "::ecsact::entt::detail::hash_vals(static_cast({}::id), {})", + "::ecsact::entt::detail::hash_vals32(static_cast({}::id), {})", compo_name, comma_delim(std::views::transform( fields, diff --git a/runtime/hash.cc b/runtime/hash.cc index 343b126..75a3a46 100644 --- a/runtime/hash.cc +++ b/runtime/hash.cc @@ -1,7 +1,29 @@ #include "ecsact/entt/detail/hash.hh" #include "xxhash.h" -auto ecsact::entt::detail::bytes_hash( // +auto ecsact::entt::detail::bytes_hash32( // + std::byte* data, + int data_length +) -> std::uint32_t { + if(data_length == sizeof(std::uint32_t)) { + auto bytes_as_u32 = std::uint32_t{}; + std::memcpy(&bytes_as_u32, data, sizeof(std::uint32_t)); + return bytes_as_u32; + } else if(data_length == sizeof(std::uint16_t)) { + auto bytes_as_u16 = std::uint16_t{}; + std::memcpy(&bytes_as_u16, data, sizeof(std::uint16_t)); + return bytes_as_u16; + } else if(data_length == 1) { + return static_cast(data[0]); + } else if(data_length == 0) { + return 0; + } + + auto hash = XXH32(data, data_length, 1); + return hash; +} + +auto ecsact::entt::detail::bytes_hash64( // std::byte* data, int data_length ) -> std::uint64_t { diff --git a/test/assoc/assoc_test.cc b/test/assoc/assoc_test.cc index 90520d7..8caefcb 100644 --- a/test/assoc/assoc_test.cc +++ b/test/assoc/assoc_test.cc @@ -1,13 +1,35 @@ #include "gtest/gtest.h" +#include "entt/entt.hpp" #include "ecsact/runtime/core.hh" -#include "ecsact/runtime/dynamic.h" - #include "assoc_test.ecsact.hh" -#include "assoc_test.ecsact.systems.hh" using namespace assoc_test; +TEST(Assoc, EnttSanityChecks) { + using namespace entt::literals; + + struct A { + int32_t n; + }; + + auto reg = entt::registry{}; + auto entity = reg.create(); + + auto other_storage_id = entt::id_type{1232131231}; + + reg.storage().emplace(entity, A{10}); + ASSERT_TRUE(reg.storage().contains(entity)); + ASSERT_FALSE(reg.storage(other_storage_id).contains(entity)); + + reg.storage(other_storage_id).emplace(entity, A{20}); + ASSERT_TRUE(reg.storage().contains(entity)); + ASSERT_TRUE(reg.storage(other_storage_id).contains(entity)); + + ASSERT_EQ(reg.storage().get(entity).n, 10); + ASSERT_EQ(reg.storage(other_storage_id).get(entity).n, 20); +} + TEST(AssocCore, EntityAssoc) { auto reg = ecsact::core::registry{"EntityAssoc"}; auto entity1 = reg.create_entity(); @@ -16,16 +38,25 @@ TEST(AssocCore, EntityAssoc) { ASSERT_FALSE(reg.has_component(entity1, entity2)); ASSERT_FALSE(reg.has_component(entity1, entity1)); - reg.add_component(entity1, EntityAssoc{entity2, 10}); + ASSERT_EQ( + reg.add_component(entity1, EntityAssoc{entity2, 10}), + ECSACT_ADD_OK + ); ASSERT_TRUE(reg.has_component(entity1, entity2)); EXPECT_FALSE(reg.has_component(entity1, entity1)); - ASSERT_EQ(reg.get_component(entity1, entity1).n, 10); + ASSERT_EQ(reg.get_component(entity1, entity2).n, 10); - reg.update_component(entity1, EntityAssoc{entity1, 12}, entity2); - ASSERT_TRUE(reg.has_component(entity1, entity1)); - ASSERT_FALSE(reg.has_component(entity1, entity2)); + ASSERT_EQ( + reg.update_component(entity1, EntityAssoc{entity1, 12}, entity2), + ECSACT_UPDATE_OK + ); + EXPECT_TRUE(reg.has_component(entity1, entity1)); + EXPECT_FALSE(reg.has_component(entity1, entity2)); - reg.add_component(entity1, EntityAssoc{entity2, 18}); + ASSERT_EQ( + reg.add_component(entity1, EntityAssoc{entity2, 18}), + ECSACT_ADD_OK + ); ASSERT_TRUE(reg.has_component(entity1, entity1)); ASSERT_TRUE(reg.has_component(entity1, entity2)); ASSERT_EQ(reg.get_component(entity1, entity1).n, 12); @@ -36,7 +67,7 @@ TEST(AssocCore, EntityAssoc) { ASSERT_TRUE(reg.has_component(entity1, entity1)); ASSERT_EQ(reg.get_component(entity1, entity1).n, 12); - reg.remove_component(entity1, entity2); + reg.remove_component(entity1, entity1); ASSERT_FALSE(reg.has_component(entity1, entity2)); ASSERT_FALSE(reg.has_component(entity1, entity1)); } From 6b1c5a2533b091d3180f27247a8aa1a675faf207 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 27 Jun 2024 13:39:53 -0700 Subject: [PATCH 15/19] feat: field index assoc test --- test/assoc/assoc_test.cc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/assoc/assoc_test.cc b/test/assoc/assoc_test.cc index 8caefcb..2594124 100644 --- a/test/assoc/assoc_test.cc +++ b/test/assoc/assoc_test.cc @@ -71,3 +71,33 @@ TEST(AssocCore, EntityAssoc) { ASSERT_FALSE(reg.has_component(entity1, entity2)); ASSERT_FALSE(reg.has_component(entity1, entity1)); } + +TEST(AssocCore, FieldAssoc) { + auto reg = ecsact::core::registry{"FieldAssoc"}; + + auto entity1 = reg.create_entity(); + auto entity2 = reg.create_entity(); + + ASSERT_FALSE(reg.has_component(entity1, 10)); + ASSERT_FALSE(reg.has_component(entity1, 11)); + + ASSERT_EQ(reg.add_component(entity1, FieldAssoc{10, 44}), ECSACT_ADD_OK); + ASSERT_TRUE(reg.has_component(entity1, 10)); + ASSERT_FALSE(reg.has_component(entity1, 11)); + + ASSERT_EQ(reg.add_component(entity1, FieldAssoc{11, 44}), ECSACT_ADD_OK); + ASSERT_TRUE(reg.has_component(entity1, 10)); + ASSERT_TRUE(reg.has_component(entity1, 11)); + + ASSERT_EQ( + reg.update_component(entity1, FieldAssoc{9, 44}, 10), + ECSACT_UPDATE_OK + ); + ASSERT_FALSE(reg.has_component(entity1, 10)); + ASSERT_TRUE(reg.has_component(entity1, 9)); + ASSERT_TRUE(reg.has_component(entity1, 11)); + + reg.remove_component(entity1, 9); + ASSERT_FALSE(reg.has_component(entity1, 9)); + ASSERT_TRUE(reg.has_component(entity1, 11)); +} From 23a2e29ee652afd28513b88a741c37ae4a95bbae Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 28 Jun 2024 08:45:22 -0700 Subject: [PATCH 16/19] fix: only assoc storage --- ecsact/entt/wrapper/dynamic.hh | 8 ++------ test/assoc/assoc_test.ecsact | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/ecsact/entt/wrapper/dynamic.hh b/ecsact/entt/wrapper/dynamic.hh index 5f45aaf..159bccc 100644 --- a/ecsact/entt/wrapper/dynamic.hh +++ b/ecsact/entt/wrapper/dynamic.hh @@ -36,12 +36,8 @@ auto context_add( } else if constexpr(C::has_assoc_fields) { auto component = static_cast(component_data); auto assoc_fields_hash = get_assoc_fields_hash(*component); - registry.template storage(assoc_fields_hash).emplace(entity, *component); - registry.template emplace>( - entity, - *component, - false - ); + auto storage_id = static_cast<::entt::id_type>(assoc_fields_hash); + registry.template storage(storage_id).emplace(entity, *component); } else { const C* component = static_cast(component_data); registry.template emplace_or_replace>(entity, *component); diff --git a/test/assoc/assoc_test.ecsact b/test/assoc/assoc_test.ecsact index 5a0b007..d4c891a 100644 --- a/test/assoc/assoc_test.ecsact +++ b/test/assoc/assoc_test.ecsact @@ -3,4 +3,3 @@ main package assoc_test; component EntityAssoc { entity e; i32 n; } component Unique { i32 my_id; } component FieldAssoc { Unique.my_id unique_id; i32 num; } - From 12e9589522512a3c3a5a6883a11f588209de85e3 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 28 Jun 2024 08:46:07 -0700 Subject: [PATCH 17/19] fix: removed duplicate in recipe --- build_recipe.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build_recipe.yml b/build_recipe.yml index a80214e..6f48e6b 100644 --- a/build_recipe.yml +++ b/build_recipe.yml @@ -57,10 +57,6 @@ sources: outdir: include/entt/entity - fetch: https://raw.githubusercontent.com/skypjack/entt/v3.12.2/src/entt/entity/sparse_set.hpp outdir: include/entt/entity - - fetch: https://raw.githubusercontent.com/skypjack/entt/v3.12.2/src/entt/entity/group.hpp - outdir: include/entt/entity - - fetch: https://raw.githubusercontent.com/skypjack/entt/v3.12.2/src/entt/entity/storage.hpp - outdir: include/entt/entity - fetch: https://raw.githubusercontent.com/skypjack/entt/v3.12.2/src/entt/entity/component.hpp outdir: include/entt/entity - fetch: https://raw.githubusercontent.com/skypjack/entt/v3.12.2/src/entt/entity/mixin.hpp From 710deaa7cc3015ca69c5621cdd0d80189083a86a Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 28 Jun 2024 13:54:09 -0700 Subject: [PATCH 18/19] chore: wip (not working --- ecsact/entt/detail/indexed_storage.hh | 7 ++ .../association/association.cc | 92 +++++++++++-------- .../association/association.hh | 6 ++ test/assoc/assoc_test.cc | 47 ++++++++++ test/assoc/assoc_test.ecsact | 9 ++ 5 files changed, 124 insertions(+), 37 deletions(-) diff --git a/ecsact/entt/detail/indexed_storage.hh b/ecsact/entt/detail/indexed_storage.hh index 48d21d5..169155d 100644 --- a/ecsact/entt/detail/indexed_storage.hh +++ b/ecsact/entt/detail/indexed_storage.hh @@ -1,11 +1,18 @@ #pragma once +#include #include "codegen_error.hh" #include "ecsact/entt/detail/registry.hh" +#include "ecsact/entt/detail/assoc_fields_hash.hh" #include "ecsact/entt/detail/codegen_error.hh" namespace ecsact::entt::detail { +template +struct multi_storage { + std::vector storage_hash_value_ids; +}; + template auto update_indexed_storage(ecsact::entt::registry_t& registry) -> void { static_assert(detail::unimplemented_by_codegen, R"( diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index 84e0789..22a477b 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -81,6 +81,30 @@ static auto push_back_unique(auto& vec, const auto& element) -> void { } } +auto provider::association::before_make_view_or_group( + codegen_plugin_context& ctx, + const common_vars& names, + std::vector& additional_view_components +) -> void { + // for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + // auto assoc_caps = + // ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); + // auto assoc_system_details = + // ecsact_entt_system_details::from_capabilities(assoc_caps); + // + // for(auto compo_id : assoc_composites.at(assoc_id)) { + // // TODO: At the time of writing this is safe. It's very possible we + // // allow actions to be referenecd in association fields in the near + // // future and at that point this must be addressed. + // auto comp_like_id = static_cast(compo_id); + // if(!assoc_system_details.get_comps.contains(comp_like_id)) { + // auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_like_id)); + // push_back_unique(additional_view_components, comp_cpp_ident); + // } + // } + // } +} + auto provider::association::after_make_view_or_group( codegen_plugin_context& ctx, const common_vars& names @@ -104,6 +128,9 @@ auto provider::association::entity_iteration( block(ctx, "for(auto entity : view)", [&] { for(auto assoc_id : assoc_ids) { + auto assoc_comp = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto assoc_comp_cpp_ident = cpp_identifier(decl_full_name(assoc_comp)); auto assoc_caps = ecsact::meta::system_assoc_capabilities(sys_like_id, assoc_id); auto assoc_system_details = @@ -112,50 +139,41 @@ auto provider::association::entity_iteration( make_view_opts.view_var_name = assoc_view_names.at(assoc_id); make_view_opts.registry_var_name = names.registry_var_name; - for(auto compo_id : assoc_composites.at(assoc_id)) { - // TODO: At the time of writing this is safe. It's very possible we - // allow actions to be referenecd in association fields in the near - // future and at that point this must be addressed. - auto comp_like_id = static_cast(compo_id); - if(!assoc_system_details.get_comps.contains(comp_like_id)) { - auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_like_id)); - push_back_unique( - make_view_opts.additional_components, - comp_cpp_ident - ); - } - } + push_back_unique( + make_view_opts.additional_components, + assoc_comp_cpp_ident + ); util::make_view(ctx, make_view_opts); } print_other_contexts(ctx, names); - for(auto&& [assoc_id, compo_ids] : assoc_composites) { - for(auto compo_id : compo_ids) { - auto field_ids = assoc_fields.at(compo_id); - auto compo_cpp_ident = cpp_identifier(decl_full_name(compo_id)); + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + auto assoc_comp_cpp_ident = cpp_identifier(decl_full_name(assoc_comp_id)); + auto assoc_comp_field_ids = + ecsact::meta::system_assoc_fields(sys_like_id, assoc_id); - ctx.write(std::format( - "{0}.storage({3}.storage<{1}>(static_cast<::entt::id_type>(::ecsact::" - "entt::detail::" - "hash_vals32({1}::" - "id, {2}))));\n", - assoc_view_names.at(assoc_id), - compo_cpp_ident, - util::comma_delim( - field_ids | - std::views::transform([&](auto field_id) -> std::string { - return std::format( - "view.get<{}>(entity).{}", - compo_cpp_ident, - ecsact::meta::field_name(compo_id, field_id) - ); - }) - ), - names.registry_var_name - )); - } + ctx.write(std::format( + "{0}.storage({1}.storage<{2}>(static_cast<::entt::id_type>(" + "::ecsact::entt::detail::hash_vals32({2}::id, {3})" + ")));\n", + assoc_view_names.at(assoc_id), + names.registry_var_name, + assoc_comp_cpp_ident, + util::comma_delim( + assoc_comp_field_ids | + std::views::transform([&](auto field_id) -> std::string { + return std::format( + "view.get<{}>(entity).{}", + assoc_comp_cpp_ident, + ecsact::meta::field_name(assoc_comp_id, field_id) + ); + }) + ) + )); } for(auto assoc_index = 0; assoc_ids.size() > assoc_index; ++assoc_index) { diff --git a/rt_entt_codegen/core/system_provider/association/association.hh b/rt_entt_codegen/core/system_provider/association/association.hh index 1bf0a81..173e651 100644 --- a/rt_entt_codegen/core/system_provider/association/association.hh +++ b/rt_entt_codegen/core/system_provider/association/association.hh @@ -23,6 +23,12 @@ public: std::function iter_func ) -> handle_exclusive_provide final; + auto before_make_view_or_group( + ecsact::codegen_plugin_context& ctx, + const ecsact::rt_entt_codegen::core::common_vars& names, + std::vector& additional_view_components + ) -> void final; + auto after_make_view_or_group( codegen_plugin_context& ctx, const common_vars& names diff --git a/test/assoc/assoc_test.cc b/test/assoc/assoc_test.cc index 2594124..d6b9200 100644 --- a/test/assoc/assoc_test.cc +++ b/test/assoc/assoc_test.cc @@ -1,11 +1,31 @@ #include "gtest/gtest.h" +#include #include "entt/entt.hpp" #include "ecsact/runtime/core.hh" +#include "ecsact/runtime/dynamic.h" #include "assoc_test.ecsact.hh" +#include "assoc_test.ecsact.systems.hh" using namespace assoc_test; +#define SET_SYSTEM_IMPL(SystemName) \ + ASSERT_TRUE(ecsact_set_system_execution_impl( \ + ecsact_id_cast(SystemName::id), \ + &assoc_test__##SystemName \ + )) +#define CLEAR_SYSTEM_IMPL(SystemName) \ + ASSERT_TRUE(ecsact_set_system_execution_impl( \ + ecsact_id_cast(SystemName::id), \ + nullptr \ + )) + +static std::atomic_int FieldAssocSystem_exec_count = 0; + +auto FieldAssocSystem::impl(context& ctx) -> void { + FieldAssocSystem_exec_count += 1; +} + TEST(Assoc, EnttSanityChecks) { using namespace entt::literals; @@ -101,3 +121,30 @@ TEST(AssocCore, FieldAssoc) { ASSERT_FALSE(reg.has_component(entity1, 9)); ASSERT_TRUE(reg.has_component(entity1, 11)); } + +TEST(AssocCore, FieldAssocExecutionCount) { + SET_SYSTEM_IMPL(FieldAssocSystem); + + auto reg = ecsact::core::registry{"FieldAssocExecutionCount"}; + + auto entity1 = reg.create_entity(); + auto entity2 = reg.create_entity(); + + reg.add_component(entity1, FieldAssoc{10, 22}); + reg.add_component(entity1, FieldAssoc{11, 30}); + reg.add_component(entity1, FieldAssoc{16, 48}); + + reg.execute_systems(); + EXPECT_EQ(FieldAssocSystem_exec_count, 0); + FieldAssocSystem_exec_count = 0; + + reg.add_component(entity2, FieldAssoc{10, 55}); + reg.add_component(entity2, A{57}); + + __debugbreak(); + reg.execute_systems(); + EXPECT_EQ(FieldAssocSystem_exec_count, 1); + FieldAssocSystem_exec_count = 0; + + CLEAR_SYSTEM_IMPL(FieldAssocSystem); +} diff --git a/test/assoc/assoc_test.ecsact b/test/assoc/assoc_test.ecsact index d4c891a..0a06ee7 100644 --- a/test/assoc/assoc_test.ecsact +++ b/test/assoc/assoc_test.ecsact @@ -3,3 +3,12 @@ main package assoc_test; component EntityAssoc { entity e; i32 n; } component Unique { i32 my_id; } component FieldAssoc { Unique.my_id unique_id; i32 num; } + +component A { i32 a; } + +system FieldAssocSystem { + readonly FieldAssoc with unique_id { + readwrite A; + } +} + From 61d4a9762eef07b413b421a4482a7da9938b1d0c Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 28 Jun 2024 17:59:56 -0700 Subject: [PATCH 19/19] feat: absolute code vomit (monday problem) --- ecsact/entt/detail/indexed_storage.hh | 16 +++- ecsact/entt/wrapper/core.hh | 8 ++ rt_entt_codegen/core/print_sys_exec.cc | 45 ++++++++++- .../association/association.cc | 75 +++++++++++++++++- .../core/system_provider/basic/basic.cc | 79 +++++++++++++++++++ .../system_provider/system_ctx_functions.cc | 30 +++++-- .../system_provider/system_ctx_functions.hh | 6 ++ rt_entt_codegen/shared/util.cc | 47 ++++++++++- rt_entt_codegen/shared/util.hh | 1 + test/assoc/assoc_test.cc | 1 - test/assoc/assoc_test.ecsact | 6 +- 11 files changed, 297 insertions(+), 17 deletions(-) diff --git a/ecsact/entt/detail/indexed_storage.hh b/ecsact/entt/detail/indexed_storage.hh index 169155d..bbc27ab 100644 --- a/ecsact/entt/detail/indexed_storage.hh +++ b/ecsact/entt/detail/indexed_storage.hh @@ -9,8 +9,22 @@ namespace ecsact::entt::detail { template -struct multi_storage { +struct multi_assoc_storage { std::vector storage_hash_value_ids; + + auto ensure(assoc_hash_value_t id) -> void { + if(std::ranges::find(storage_hash_value_ids, id) == + storage_hash_value_ids.end()) { + storage_hash_value_ids.emplace_back(id); + } + } + + auto erase(assoc_hash_value_t id) -> void { + auto itr = std::ranges::find(storage_hash_value_ids, id); + if(itr != storage_hash_value_ids.end()) { + storage_hash_value_ids.erase(itr); + } + } }; template diff --git a/ecsact/entt/wrapper/core.hh b/ecsact/entt/wrapper/core.hh index 5754e33..70317e4 100644 --- a/ecsact/entt/wrapper/core.hh +++ b/ecsact/entt/wrapper/core.hh @@ -10,6 +10,7 @@ #include "ecsact/entt/error_check.hh" #include "ecsact/entt/detail/execution_events_collector.hh" #include "ecsact/entt/detail/assoc_fields_hash.hh" +#include "ecsact/entt/detail/indexed_storage.hh" namespace ecsact::entt::wrapper::core { @@ -73,6 +74,7 @@ inline auto add_component( // [[maybe_unused]] ecsact_component_id component_id, const void* component_data ) -> ecsact_add_error { + using ecsact::entt::detail::multi_assoc_storage; auto& reg = ecsact::entt::get_registry(registry_id); auto entity = ecsact::entt::entity_id{entity_id}; assert(C::id == component_id); @@ -92,6 +94,12 @@ inline auto add_component( // ecsact::entt::detail::get_assoc_fields_hash(*comp); auto storage_id = static_cast<::entt::id_type>(assoc_fields_hash); reg.storage(storage_id).emplace(entity, *comp); + if(!reg.all_of>(entity)) { + reg.emplace>(entity).ensure(assoc_fields_hash); + } else { + auto& multi_storage = reg.get>(entity); + multi_storage.ensure(assoc_fields_hash); + } } else { auto comp = static_cast(component_data); reg.emplace>(entity, *comp, false); diff --git a/rt_entt_codegen/core/print_sys_exec.cc b/rt_entt_codegen/core/print_sys_exec.cc index ebd9bdf..a1249b4 100644 --- a/rt_entt_codegen/core/print_sys_exec.cc +++ b/rt_entt_codegen/core/print_sys_exec.cc @@ -35,11 +35,13 @@ concept system_or_action = 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::block_printer; using ecsact::cpp_codegen_plugin_util::comma_delim; using ecsact::meta::decl_full_name; using ecsact::rt_entt_codegen::ecsact_entt_system_details; using ecsact::rt_entt_codegen::system_comps_with_caps; using ecsact::rt_entt_codegen::system_like_id_variant; +using ecsact::rt_entt_codegen::core::provider::context_view_storage_struct_impl; using ecsact::rt_entt_codegen::core::provider::handle_exclusive_provide; using ecsact::rt_entt_codegen::core::provider::system_provider; using ecsact::rt_entt_codegen::system_util::is_trivial_system; @@ -316,9 +318,12 @@ static auto print_system_execution_context( "struct {}: ecsact_system_execution_context ", context_type_name ); + auto system_capabilities = + ecsact::meta::system_capabilities_list(sys_like_id); block(ctx, struct_header, [&] { ctx.write("view_t* view;\n"); + context_view_storage_struct_impl(ctx, system_capabilities); for(const auto& provider : system_providers) { provider->context_function_header(ctx, names); @@ -388,18 +393,56 @@ static auto setup_system_providers(system_like_id_variant sys_like_id return system_providers; } +static auto get_assoc_comps( // + system_like_id_variant sys_like_id +) -> std::vector { + auto assoc_comps = std::vector{}; + for(auto assoc_id : ecsact::meta::system_assoc_ids(sys_like_id)) { + auto assoc_comp_id = + ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); + if(std::ranges::find(assoc_comps, assoc_comp_id) == assoc_comps.end()) { + assoc_comps.push_back(assoc_comp_id); + } + } + + return assoc_comps; +} + static auto print_execute_systems( ecsact::codegen_plugin_context& ctx, system_like_id_variant sys_like_id, const common_vars names ) -> void { + auto assoc_comps = get_assoc_comps(sys_like_id); + auto assoc_view_block = std::optional{}; + + // if(!assoc_comps.empty()) { + // ctx.write(std::format( + // "auto assoc_multi_storage_view = {}.view<{}>();\n", + // names.registry_var_name, + // comma_delim( + // assoc_comps | std::views::transform([](auto comp_id) -> std::string { + // auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_id)); + // return std::format( + // "ecsact::entt::detail::multi_assoc_storage<{}>", + // comp_cpp_ident + // ); + // }) + // ) + // )); + // + // ctx.write("for(auto assoc_multi_entity : assoc_multi_storage_view)"); + // assoc_view_block.emplace(ctx); + // } + auto sys_caps = ecsact::meta::system_capabilities(sys_like_id); auto system_providers = setup_system_providers(sys_like_id); auto sys_details = ecsact_entt_system_details::from_system_like(sys_like_id); auto make_view_opts = make_view_options(sys_details); make_view_opts.registry_var_name = names.registry_var_name; - make_view_opts.view_var_name = "view"; make_view_opts.sys_like_id = sys_like_id; + make_view_opts.without_multi_component_storage = false; + make_view_opts.view_var_name = "view"; for(const auto& provider : system_providers) { provider->initialization(ctx, names); diff --git a/rt_entt_codegen/core/system_provider/association/association.cc b/rt_entt_codegen/core/system_provider/association/association.cc index 22a477b..b3a9428 100644 --- a/rt_entt_codegen/core/system_provider/association/association.cc +++ b/rt_entt_codegen/core/system_provider/association/association.cc @@ -119,6 +119,47 @@ auto provider::association::context_function_other( return HANDLED; } +template +static auto get_assoc_fields(CompositeID compo_id +) -> std::vector { + auto result = std::vector{}; + + for(auto field_id : ecsact::meta::get_field_ids(compo_id)) { + auto field_type = ecsact::meta::get_field_type(compo_id, field_id); + if(field_type.kind == ECSACT_TYPE_KIND_BUILTIN && + field_type.type.builtin == ECSACT_ENTITY_TYPE) { + result.push_back(field_id); + } + + if(field_type.kind == ECSACT_TYPE_KIND_FIELD_INDEX) { + result.push_back(field_id); + } + } + + return result; +} + +static auto has_assoc_fields(ecsact::rt_entt_codegen::system_like_id_variant id +) -> bool { + for(auto&& [comp_id, _] : ecsact::meta::system_capabilities_list(id)) { + if(!get_assoc_fields(comp_id).empty()) { + return true; + } + } + return false; +} + +static auto get_first_assoc_comp( + ecsact::rt_entt_codegen::system_like_id_variant id +) -> std::optional { + for(auto&& [comp_id, _] : ecsact::meta::system_capabilities_list(id)) { + if(!get_assoc_fields(comp_id).empty()) { + return comp_id; + } + } + return {}; +} + auto provider::association::entity_iteration( codegen_plugin_context& ctx, const common_vars& names, @@ -126,7 +167,26 @@ auto provider::association::entity_iteration( ) -> handle_exclusive_provide { auto assoc_ids = ecsact::meta::system_assoc_ids(sys_like_id); + auto assoc_multi_view_block = + std::optional{}; block(ctx, "for(auto entity : view)", [&] { + if(has_assoc_fields(sys_like_id)) { + ctx.write(std::format( // + "for(auto storage_id : " + "view.get>(entity)." + "storage_hash_value_ids)", + cpp_identifier(decl_full_name(get_first_assoc_comp(sys_like_id).value()) + ) + )); + assoc_multi_view_block.emplace(ctx); + ctx.write(std::format( + "context.storage.c{} = ®istry.storage<{}>(storage_id);", + static_cast(get_first_assoc_comp(sys_like_id).value()), + cpp_identifier(decl_full_name(get_first_assoc_comp(sys_like_id).value()) + ) + )); + } + for(auto assoc_id : assoc_ids) { auto assoc_comp = ecsact::meta::system_assoc_component_id(sys_like_id, assoc_id); @@ -167,8 +227,8 @@ auto provider::association::entity_iteration( assoc_comp_field_ids | std::views::transform([&](auto field_id) -> std::string { return std::format( - "view.get<{}>(entity).{}", - assoc_comp_cpp_ident, + "context.storage.c{}->get(entity).{}", + static_cast(assoc_comp_id), ecsact::meta::field_name(assoc_comp_id, field_id) ); }) @@ -264,6 +324,7 @@ auto provider::association::print_other_contexts( using std::views::transform; ctx.write(std::format("{}_t* view;\n", assoc_view_names.at(assoc_id))); + context_view_storage_struct_impl(ctx, assoc_caps); ctx.write("\n"); print_other_ctx_action(ctx); print_other_ctx_add( @@ -297,6 +358,16 @@ auto provider::association::print_other_contexts( ctx.write(struct_name, " ", context_name, ";\n\n"); ctx.write(context_name, ".view = &", assoc_view_names.at(assoc_id), ";\n"); + for(auto&& [comp_id, _] : assoc_caps) { + auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_id)); + ctx.write(std::format( + "{}.storage.c{} = {}.storage<{}>();\n", + context_name, + static_cast(comp_id), + assoc_view_names.at(assoc_id), + comp_cpp_ident + )); + } ctx.write(context_name, ".parent_ctx = nullptr;\n\n"); ctx.write(context_name, ".registry = &", names.registry_var_name, ";\n"); } diff --git a/rt_entt_codegen/core/system_provider/basic/basic.cc b/rt_entt_codegen/core/system_provider/basic/basic.cc index 344f3ee..37509e4 100644 --- a/rt_entt_codegen/core/system_provider/basic/basic.cc +++ b/rt_entt_codegen/core/system_provider/basic/basic.cc @@ -6,6 +6,9 @@ #include "ecsact/cpp_codegen_plugin_util.hh" #include "rt_entt_codegen/core/system_provider/system_ctx_functions.hh" +using ecsact::cc_lang_support::cpp_identifier; +using ecsact::meta::decl_full_name; + using namespace ecsact::rt_entt_codegen::core; auto provider::basic::initialization( @@ -110,6 +113,47 @@ auto provider::basic::system_impl( return HANDLED; } +template +static auto get_assoc_fields(CompositeID compo_id +) -> std::vector { + auto result = std::vector{}; + + for(auto field_id : ecsact::meta::get_field_ids(compo_id)) { + auto field_type = ecsact::meta::get_field_type(compo_id, field_id); + if(field_type.kind == ECSACT_TYPE_KIND_BUILTIN && + field_type.type.builtin == ECSACT_ENTITY_TYPE) { + result.push_back(field_id); + } + + if(field_type.kind == ECSACT_TYPE_KIND_FIELD_INDEX) { + result.push_back(field_id); + } + } + + return result; +} + +static auto has_assoc_fields(ecsact::rt_entt_codegen::system_like_id_variant id +) -> bool { + for(auto&& [comp_id, _] : ecsact::meta::system_capabilities_list(id)) { + if(!get_assoc_fields(comp_id).empty()) { + return true; + } + } + return false; +} + +static auto get_first_assoc_comp( + ecsact::rt_entt_codegen::system_like_id_variant id +) -> std::optional { + for(auto&& [comp_id, _] : ecsact::meta::system_capabilities_list(id)) { + if(!get_assoc_fields(comp_id).empty()) { + return comp_id; + } + } + return {}; +} + auto provider::basic::entity_iteration( ecsact::codegen_plugin_context& ctx, const ecsact::rt_entt_codegen::core::common_vars& names, @@ -118,6 +162,26 @@ auto provider::basic::entity_iteration( using ecsact::cpp_codegen_plugin_util::block; block(ctx, "for(ecsact::entt::entity_id entity : view)", [&] { + auto assoc_multi_view_block = + std::optional{}; + + if(has_assoc_fields(sys_like_id)) { + ctx.write(std::format( // + "for(auto storage_id : " + "view.get>(entity)." + "storage_hash_value_ids)", + cpp_identifier(decl_full_name(get_first_assoc_comp(sys_like_id).value()) + ) + )); + assoc_multi_view_block.emplace(ctx); + ctx.write(std::format( + "context.storage.c{} = ®istry.storage<{}>(storage_id);", + static_cast(get_first_assoc_comp(sys_like_id).value()), + cpp_identifier(decl_full_name(get_first_assoc_comp(sys_like_id).value()) + ) + )); + } + iter_func(); }); return HANDLED; @@ -145,6 +209,21 @@ auto provider::basic::provide_context_init( ); ctx.write("context.parent_ctx = ", names.parent_context_var_name, ";\n"); ctx.write("context.view = &view;\n\n"); + for(auto&& [comp_id, _] : + ecsact::meta::system_capabilities_list(sys_like_id)) { + // TODO: Replace this garbage code. just for POC + if(get_assoc_fields(comp_id).empty()) { + continue; + } + + auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_id)); + ctx.write(std::format( + "context.storage.c{} = view.storage<{}>();\n", + static_cast(comp_id), + comp_cpp_ident + )); + } + return HANDLED; } diff --git a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc index c655b34..da66bc8 100644 --- a/rt_entt_codegen/core/system_provider/system_ctx_functions.cc +++ b/rt_entt_codegen/core/system_provider/system_ctx_functions.cc @@ -10,6 +10,25 @@ using ecsact::cpp_codegen_plugin_util::block; using ecsact::meta::decl_full_name; using ecsact::rt_entt_codegen::util::is_transient_component; +auto ecsact::rt_entt_codegen::core::provider::context_view_storage_struct_impl( + ecsact::codegen_plugin_context& ctx, + std::vector> + system_caps +) -> void { + block(ctx, "struct", [&] { + for(auto i = 0; system_caps.size() > i; ++i) { + auto comp_id = system_caps.at(i).first; + auto comp_cpp_ident = cpp_identifier(decl_full_name(comp_id)); + ctx.write(std::format( + "::entt::basic_storage<{}>* c{} = nullptr;\n", + comp_cpp_ident, + static_cast(comp_id) + )); + } + }); + ctx.write(" storage;\n"); +} + auto ecsact::rt_entt_codegen::core::provider::context_action_impl( ecsact::codegen_plugin_context& ctx, const system_like_id_variant& sys_like_id @@ -184,13 +203,12 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl( cpp_comp_full_name, "::id) == component_id);\n" ); - ctx.write( - "*static_cast<::", + ctx.write(std::format( + "*static_cast<::{}*>(out_component_data) = " + "storage.c{}->get(entity);", cpp_comp_full_name, - "*>(out_component_data) = view->get<::", - cpp_comp_full_name, - ">(entity);" - ); + static_cast(comp_id) + )); return; } diff --git a/rt_entt_codegen/core/system_provider/system_ctx_functions.hh b/rt_entt_codegen/core/system_provider/system_ctx_functions.hh index 8d1005c..88cfa87 100644 --- a/rt_entt_codegen/core/system_provider/system_ctx_functions.hh +++ b/rt_entt_codegen/core/system_provider/system_ctx_functions.hh @@ -8,6 +8,12 @@ namespace ecsact::rt_entt_codegen::core::provider { using capability_t = std::unordered_map; +auto context_view_storage_struct_impl( // + ecsact::codegen_plugin_context& ctx, + std::vector> + caps +) -> void; + auto context_action_impl( ecsact::codegen_plugin_context& ctx, const system_like_id_variant& sys_like_id diff --git a/rt_entt_codegen/shared/util.cc b/rt_entt_codegen/shared/util.cc index 831a654..ffe1f16 100644 --- a/rt_entt_codegen/shared/util.cc +++ b/rt_entt_codegen/shared/util.cc @@ -19,11 +19,51 @@ auto ecsact::rt_entt_codegen::util::make_view( // ".view<" ); + // components that may have multiple instances + auto multi_components = std::vector{}; + auto is_multi_component = [&](auto id) { + auto itr = std::ranges::find( // + multi_components, + ecsact_id_cast(id) + ); + return itr != multi_components.end(); + }; + + if(!opts.without_multi_component_storage) { + for(auto assoc_info : opts.details.association_details) { + if(!is_multi_component(assoc_info.component_id)) { + multi_components.push_back(assoc_info.component_id); + } + } + } + + auto exclude_multi_components = [&] { + return std::views::filter([&](auto id) -> bool { + return !is_multi_component(id); + }); + }; + ctx.write(comma_delim( - opts.details.get_comps | transform(decl_cpp_ident) + opts.details.get_comps | exclude_multi_components() | + transform(decl_cpp_ident) + )); + + if(!multi_components.empty() && + !(opts.details.get_comps | exclude_multi_components()).empty()) { + ctx.write(", "); + } + + ctx.write(comma_delim( + multi_components | // + transform([](auto id) -> std::string { + return std::format( + "ecsact::entt::detail::multi_assoc_storage<{}>", + decl_cpp_ident(id) + ); + }) )); - for(auto comp_id : opts.details.writable_comps) { + for(auto comp_id : opts.details.writable_comps | exclude_multi_components()) { auto comp_name = decl_cpp_ident(comp_id); opts.additional_components.push_back(std::format( @@ -79,7 +119,8 @@ auto ecsact::rt_entt_codegen::util::make_view( // for(auto&& [compo_id, fields] : indexed_fields) { auto compo_name = cpp_identifier(decl_full_name(compo_id)); auto hash_fields_str = std::format( - "::ecsact::entt::detail::hash_vals32(static_cast({}::id), {})", + "::ecsact::entt::detail::hash_vals32(static_cast({}::id), " + "{})", compo_name, comma_delim(std::views::transform( fields, diff --git a/rt_entt_codegen/shared/util.hh b/rt_entt_codegen/shared/util.hh index 45c7ad2..71111c5 100644 --- a/rt_entt_codegen/shared/util.hh +++ b/rt_entt_codegen/shared/util.hh @@ -278,6 +278,7 @@ struct make_view_options { std::vector additional_components; std::vector additional_exclude_components; std::optional sys_like_id; + bool without_multi_component_storage; const ecsact_entt_system_details& details; diff --git a/test/assoc/assoc_test.cc b/test/assoc/assoc_test.cc index d6b9200..6b639bd 100644 --- a/test/assoc/assoc_test.cc +++ b/test/assoc/assoc_test.cc @@ -141,7 +141,6 @@ TEST(AssocCore, FieldAssocExecutionCount) { reg.add_component(entity2, FieldAssoc{10, 55}); reg.add_component(entity2, A{57}); - __debugbreak(); reg.execute_systems(); EXPECT_EQ(FieldAssocSystem_exec_count, 1); FieldAssocSystem_exec_count = 0; diff --git a/test/assoc/assoc_test.ecsact b/test/assoc/assoc_test.ecsact index 0a06ee7..24ff1c8 100644 --- a/test/assoc/assoc_test.ecsact +++ b/test/assoc/assoc_test.ecsact @@ -5,10 +5,10 @@ component Unique { i32 my_id; } component FieldAssoc { Unique.my_id unique_id; i32 num; } component A { i32 a; } +component B; system FieldAssocSystem { - readonly FieldAssoc with unique_id { - readwrite A; - } + readonly FieldAssoc; + adds B; }