Skip to content

chore: refactor entity entt <-> ecsact entity IDs #57

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2023
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
93 changes: 33 additions & 60 deletions ecsact/entt/detail/registry_info.hh
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,19 @@
#include "ecsact/cpp/type_info.hh"
#include "ecsact/entt/system_view.hh"
#include "ecsact/entt/event_markers.hh"
#include "ecsact/entt/entity.hh"
#include "ecsact/entt/detail/internal_markers.hh"

#include "meta_util.hh"

namespace ecsact_entt_rt {
using entity_id_map_t = std::unordered_map<ecsact_entity_id, entt::entity>;

template<typename Package>
struct registry_info {
using package = Package;

std::optional<std::reference_wrapper<std::mutex>> mutex;
::entt::registry registry;
entity_id_map_t entities_map;

/**
* Index of this vector is a statically casted EnTT ID
*/
std::vector<ecsact_entity_id> _ecsact_entity_ids;

ecsact_entity_id last_entity_id{};

struct create_new_entity_result {
entt::entity entt_entity_id;
ecsact_entity_id ecsact_entity_id;
};

void init_registry() {
using ecsact::entt::component_added;
Expand All @@ -64,18 +51,19 @@ struct registry_info {
using boost::mp11::mp_with_index;
using ecsact::entt::detail::association;

auto entity_field = field.template get<ecsact_entity_id>(&component);
auto entity_field_entt = entities_map.at(entity_field);
ecsact::entt::entity_id entity_field =
field.template get<ecsact_entity_id>(&component);

// TODO(zaucy): Increasing the mp_with_index number causes really long
// compile times. Iterating over the available associations
// would perform better here.
assert(field.offset < 32);
mp_with_index<32>(field.offset, [&](auto I) {
if(registry.all_of<association<C, I>>(entity_field_entt)) {
auto& assoc_comp = registry.get<association<C, I>>(entity_field_entt);
if(registry.all_of<association<C, I>>(entity_field)) {
auto& assoc_comp = registry.get<association<C, I>>(entity_field);
assoc_comp.ref_count += 1;
} else {
registry.emplace<association<C, I>>(entity_field_entt, 1);
registry.emplace<association<C, I>>(entity_field, 1);
}
});
}
Expand All @@ -88,30 +76,31 @@ struct registry_info {
using boost::mp11::mp_with_index;
using ecsact::entt::detail::association;

auto entity_field = field.template get<ecsact_entity_id>(&component);
auto entity_field_entt = entities_map.at(entity_field);
ecsact::entt::entity_id entity_field =
field.template get<ecsact_entity_id>(&component);

assert(field.offset < 32);
// TODO(zaucy): Increasing the mp_with_index number causes really long
// compile times. Iterating over the available associations
// would perform better here.
mp_with_index<32>(field.offset, [&](auto I) {
auto& assoc_comp = registry.get<association<C, I>>(entity_field_entt);
auto& assoc_comp = registry.get<association<C, I>>(entity_field);
assoc_comp.ref_count -= 1;
if(assoc_comp.ref_count == 0) {
registry.erase<association<C, I>>(entity_field_entt);
registry.erase<association<C, I>>(entity_field);
}
});
}

template<typename C>
requires(std::is_empty_v<C>)
void add_component(::entt::entity entity) {
void add_component(ecsact::entt::entity_id entity) {
registry.emplace<C>(entity);
}

template<typename C, typename... Args>
requires(!std::is_empty_v<C>)
void add_component(::entt::entity entity, Args&&... args) {
void add_component(ecsact::entt::entity_id entity, Args&&... args) {
using boost::mp11::mp_with_index;
using ecsact::entt::detail::mp_for_each_available_component;

Expand Down Expand Up @@ -142,7 +131,7 @@ struct registry_info {
}

template<typename C>
void remove_component(::entt::entity entity) {
void remove_component(ecsact::entt::entity_id entity) {
using ecsact::entt::detail::mp_for_each_available_component;

constexpr auto fields_info = ecsact::fields_info<C>();
Expand All @@ -168,32 +157,27 @@ struct registry_info {
}

/** @internal */
inline auto _create_entity(ecsact_entity_id ecsact_entity_id) {
auto new_entt_entity_id = registry.create();
entities_map[ecsact_entity_id] = new_entt_entity_id;
_ecsact_entity_ids.resize(static_cast<size_t>(new_entt_entity_id) + 1);
_ecsact_entity_ids[_ecsact_entity_ids.size() - 1] = ecsact_entity_id;
return new_entt_entity_id;
inline auto _create_entity( //
ecsact::entt::entity_id entity
) -> ecsact::entt::entity_id {
if(registry.valid(entity)) {
return entity;
}

auto new_entity = registry.create(entity.as_entt());
// Our valid check above should have allowed this to happen
assert(new_entity == entity.as_entt());
return new_entity;
}

/** @internal */
inline create_new_entity_result _create_entity() {
auto new_entity_id =
static_cast<ecsact_entity_id>(static_cast<int>(last_entity_id) + 1);
while(entities_map.contains(new_entity_id)) {
new_entity_id =
static_cast<ecsact_entity_id>(static_cast<int>(new_entity_id) + 1);
}
last_entity_id = new_entity_id;
return {
.entt_entity_id = _create_entity(new_entity_id),
.ecsact_entity_id = new_entity_id,
};
inline auto _create_entity() -> ecsact::entt::entity_id {
return registry.create();
}

// Creates an entity and also makes sure there is a matching one in the
// pending registry
inline auto create_entity(ecsact_entity_id ecsact_entity_id) {
inline auto create_entity( //
ecsact::entt::entity_id ecsact_entity_id
) -> ecsact::entt::entity_id {
std::scoped_lock lk(mutex->get());
return _create_entity(ecsact_entity_id);
}
Expand All @@ -203,19 +187,8 @@ struct registry_info {
return _create_entity();
}

inline void destroy_entity(ecsact_entity_id entity_id) {
auto entt_entity_id = entities_map.at(entity_id);

registry.destroy(entt_entity_id);
entities_map.erase(entity_id);
}

entt::entity get_entt_entity_id(ecsact_entity_id ecsact_entity_id) const {
return entities_map.at(ecsact_entity_id);
}

ecsact_entity_id get_ecsact_entity_id(entt::entity entt_entity_id) const {
return _ecsact_entity_ids.at(static_cast<size_t>(entt_entity_id));
inline void destroy_entity(ecsact::entt::entity_id entity_id) {
registry.destroy(entity_id);
}
};
} // namespace ecsact_entt_rt
38 changes: 16 additions & 22 deletions ecsact/entt/detail/system_execution_context.hh
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ struct system_execution_context_base {
using cptr_t = struct ::ecsact_system_execution_context*;
using const_cptr_t = const struct ::ecsact_system_execution_context*;

::entt::entity entity;
const cptr_t parent;
const void* action;
ecsact::entt::entity_id entity;
const cptr_t parent;
const void* action;

system_execution_context_base(
::entt::entity entity,
Expand All @@ -48,13 +48,11 @@ struct system_execution_context_base {
: entity(entity), parent(parent), action(action) {
}

virtual ~system_execution_context_base() {
}

virtual auto other(ecsact_entity_id other_entity)
-> ecsact_system_execution_context* = 0;
virtual ~system_execution_context_base() = default;

virtual auto get_ecsact_entity_id() -> ecsact_entity_id const = 0;
virtual auto other( //
ecsact::entt::entity_id other_entity
) -> ecsact_system_execution_context* = 0;

virtual auto generate(
int component_count,
Expand Down Expand Up @@ -376,7 +374,7 @@ struct system_execution_context : system_execution_context_base {
using ecsact::entt::detail::mp_for_each_available_component;
using ecsact::entt::detail::pending_add;

auto new_entity = info.create_entity().entt_entity_id;
auto new_entity = info.create_entity();
info.registry.template emplace<created_entity>(
new_entity,
ecsact_generated_entity
Expand All @@ -401,8 +399,9 @@ struct system_execution_context : system_execution_context_base {
}
}

auto other(ecsact_entity_id other_entity)
-> ecsact_system_execution_context* override {
auto other( //
ecsact::entt::entity_id other_entity
) -> ecsact_system_execution_context* override {
using boost::mp11::mp_first;
using boost::mp11::mp_for_each;
using boost::mp11::mp_second;
Expand All @@ -422,13 +421,12 @@ struct system_execution_context : system_execution_context_base {
constexpr std::size_t offset = Assoc::field_offset;
const ComponentT& comp = info.registry.template get<ComponentT>(entity);

auto field_entity_value = *reinterpret_cast<const ecsact_entity_id*>(
reinterpret_cast<const char*>(&comp) + offset
);
ecsact::entt::entity_id field_entity_value =
*reinterpret_cast<const ecsact_entity_id*>(
reinterpret_cast<const char*>(&comp) + offset
);

if(field_entity_value == other_entity) {
auto entt_field_entity_value =
info.get_entt_entity_id(field_entity_value);
using boost::mp11::mp_size;
mp_with_index<mp_size<associations>::value>(assoc_index, [&](auto I) {
using other_context_t = std::tuple_element_t<I, others_t>;
Expand All @@ -449,7 +447,7 @@ struct system_execution_context : system_execution_context_base {
_c_ctx.system_id,
assoc_view,
empty_views, // see static assertion above
entt_field_entity_value,
field_entity_value,
parent,
action
);
Expand All @@ -468,10 +466,6 @@ struct system_execution_context : system_execution_context_base {

return return_context;
}

auto get_ecsact_entity_id() -> ecsact_entity_id const override {
return info.get_ecsact_entity_id(entity);
}
};

} // namespace ecsact_entt_rt
60 changes: 60 additions & 0 deletions ecsact/entt/entity.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

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

namespace ecsact::entt {

/**
* The Ecsact and EnTT entity IDs are supposed to be 1:1. This class serves to
* make using either trivial.
*/
class entity_id {
std::int32_t _id;

public:
inline entity_id(::entt::entity entt_entity)
: _id(reinterpret_cast<std::int32_t&>(entt_entity)) {
}

inline entity_id(ecsact_entity_id ecsact_entity)
: _id(reinterpret_cast<std::int32_t&>(ecsact_entity)) {
}

entity_id(const entity_id&) = default;
entity_id(entity_id&&) = default;

auto operator=(const entity_id&) -> entity_id& = default;
auto operator=(entity_id&&) -> entity_id& = default;

auto operator<=>(const entity_id&) const = default;

inline auto operator=(::entt::entity entt_entity) noexcept -> entity_id& {
_id = reinterpret_cast<std::int32_t&>(entt_entity);
return *this;
}

inline auto operator=(ecsact_entity_id ecsact_entity) noexcept -> entity_id& {
_id = reinterpret_cast<std::int32_t&>(ecsact_entity);
return *this;
}

inline operator ecsact_entity_id() const noexcept {
return reinterpret_cast<const ecsact_entity_id&>(_id);
}

inline operator ::entt::entity() const noexcept {
return reinterpret_cast<const ::entt::entity&>(_id);
}

[[nodiscard]] inline auto as_ecsact() const noexcept -> ecsact_entity_id {
return reinterpret_cast<const ecsact_entity_id&>(_id);
}

[[nodiscard]] inline auto as_entt() const noexcept -> ::entt::entity {
return reinterpret_cast<const ::entt::entity&>(_id);
}
};

} // namespace ecsact::entt
Loading