Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ ecsact_build_recipe(
"ecsact_execute_systems",
"ecsact_create_registry",
"ecsact_clone_registry",
"ecsact_hash_registry",
"ecsact_destroy_registry",
"ecsact_clear_registry",
"ecsact_create_entity",
Expand Down
2 changes: 2 additions & 0 deletions ecsact/entt/registry_util.hh
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ auto copy_components( //
::entt::registry& dst
) -> void;

auto hash_registry(const ::entt::registry& reg) -> std::uint64_t;

} // namespace ecsact::entt
1 change: 1 addition & 0 deletions rt_entt_codegen/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ _CORE_CODEGEN_METHODS = {
"system_notify": ["//rt_entt_codegen/shared:system_util"],
"update_beforechange": [],
"copy_components": [],
"hash_registry": [],
}

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

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

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

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

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

auto printer = //
method_printer{ctx, "ecsact::entt::hash_registry"}
.parameter("const ::entt::registry&", "reg")
.return_type("std::uint64_t");

ctx.writef("auto* state = XXH3_createState();\n");
ctx.writef("if(!state) {{ return 0; }}\n");
ctx.writef("XXH3_64bits_reset(state);\n");

// XXH3_64bits_update(state, buffer, count);

block(
ctx,
"for(auto&& [entity] : reg.template storage<::entt::entity>()->each())",
[&] {
ctx.writef("XXH3_64bits_update(state, &entity, sizeof(entity));\n");
ctx.writef(
"auto has_states = std::array<bool, {}>{{\n",
details.all_components.size() + details.all_systems.size()
);
for(auto comp_id : details.all_components) {
const auto cpp_comp_name = cpp_identifier(decl_full_name(comp_id));
ctx.writef("\treg.all_of<{}>(entity),\n", cpp_comp_name);
}

for(auto sys_id : details.all_systems) {
const auto system_name = cpp_identifier(decl_full_name(sys_id));
const auto pending_lazy_exec_struct = std::format(
"::ecsact::entt::detail::pending_lazy_execution<::{}>",
system_name
);
ctx.writef("\treg.all_of<{}>(entity),\n", pending_lazy_exec_struct);
}

ctx.writef("\n}};\n");
ctx.writef(
"XXH3_64bits_update(state, has_states.data(), sizeof(bool) * "
"has_states.size());\n"
);
}
);

ctx.writef("\n");

for(auto comp_id : details.all_components) {
const auto cpp_comp_name = cpp_identifier(decl_full_name(comp_id));
if(ecsact::meta::get_field_ids(comp_id).empty()) {
// tags are covered in the `has_states` above already
continue;
}

block(
ctx,
std::format(
"for(auto&& [entity, comp] : reg.view<{}>().each())",
cpp_comp_name
),
[&] {
auto field_ids = ecsact::meta::get_field_ids(comp_id);
for(auto field_id : field_ids) {
auto field_name = ecsact::meta::field_name(comp_id, field_id);
ctx.writef(
"XXH3_64bits_update(state, &comp.{0}, "
"sizeof(decltype(comp.{0})));\n",
field_name
);
}
}
);
ctx.writef("\n");
}

ctx.writef("auto result = XXH3_64bits_digest(state);\n");
ctx.writef("XXH3_freeState(state);\n");
ctx.writef("return result;\n");
}
2 changes: 2 additions & 0 deletions rt_entt_codegen/rt_entt_codegen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ void ecsact_codegen_plugin(
inc_header(ctx, "ecsact/entt/wrapper/core.hh");
inc_header(ctx, "ecsact/entt/wrapper/dynamic.hh");
inc_header(ctx, "ecsact/entt/error_check.hh");
inc_header(ctx, "xxhash.h");
ctx.write("#include <execution>\n");

ctx.write("\n");
Expand Down Expand Up @@ -351,6 +352,7 @@ void ecsact_codegen_plugin(
core::print_execute_system_like_template_specializations(ctx, details);
core::print_init_registry_storage(ctx, details);
core::print_copy_components(ctx, details);
core::print_hash_registry(ctx, details);
core::print_apply_streaming_data(ctx, details);
core::print_trigger_ecsact_events_minimal(ctx, details);
core::print_trigger_ecsact_events_all(ctx, details);
Expand Down
5 changes: 5 additions & 0 deletions runtime/ecsact_rt_entt_core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ auto ecsact_clone_registry( //
return cloned_reg_id;
}

auto ecsact_hash_registry(ecsact_registry_id reg_id) -> uint64_t {
auto& reg = ecsact::entt::get_registry(reg_id);
return ecsact::entt::hash_registry(reg);
}

void ecsact_clear_registry(ecsact_registry_id reg_id) {
auto& reg = ecsact::entt::get_registry(reg_id);
reg = {};
Expand Down
16 changes: 16 additions & 0 deletions test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,19 @@ cc_test(
"@googletest//:gtest_main",
],
)

cc_test(
name = "hash_test",
srcs = [
"hash_test.cc",
"system_impls.cc",
":ecsact_cc_system_impl_srcs",
],
args = ["--gtest_catch_exceptions=0"],
copts = copts,
deps = [
":runtime",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)
48 changes: 48 additions & 0 deletions test/hash_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "gtest/gtest.h"

#include "ecsact/runtime/core.hh"
#include "runtime_test.ecsact.hh"

TEST(Core, HashRegistry) {
std::srand(std::time(nullptr));

auto reg = ecsact::core::registry{"Hash Test"};

auto hash_empty = reg.hash();

for(auto i = 0; 10000 > i; ++i) {
auto entity = reg.create_entity();
reg.add_component(entity, runtime_test::ComponentA{std::rand()});
reg.add_component(entity, runtime_test::ComponentB{std::rand()});
reg.add_component<runtime_test::TriggerTag>(entity);
}

auto hash = reg.hash();

ASSERT_NE(hash_empty, hash);

auto new_entity = reg.create_entity();
auto hash_after_new_entity = reg.hash();
ASSERT_NE(hash, hash_after_new_entity);
ASSERT_NE(hash_empty, hash_after_new_entity);

reg.add_component(new_entity, runtime_test::ComponentA{std::rand()});
auto hash_after_add_component = reg.hash();
ASSERT_NE(hash, hash_after_add_component);
ASSERT_NE(hash_after_new_entity, hash_after_add_component);
ASSERT_NE(hash_empty, hash_after_add_component);

ecsact_destroy_entity(reg.id(), new_entity);
auto hash_after_destroy_entity = reg.hash();

ASSERT_NE(hash_after_new_entity, hash_after_add_component);
ASSERT_NE(hash_after_new_entity, hash_after_destroy_entity);
ASSERT_NE(hash_empty, hash_after_destroy_entity);
ASSERT_EQ(hash, hash_after_destroy_entity); // reset to orig

reg.clear();
auto hash_after_clear = reg.hash();
ASSERT_NE(hash, hash_after_clear);
ASSERT_EQ(hash_empty, hash_after_clear);
ASSERT_NE(hash_after_new_entity, hash_after_clear);
}
Loading