registry::stomp supports foreign registries (close #315)

This commit is contained in:
Michele Caini
2019-11-07 00:09:27 +01:00
parent f498b8a049
commit 28e5267132
3 changed files with 50 additions and 5 deletions

2
TODO
View File

@@ -21,7 +21,6 @@
- use direct access (pool-like) also for context variables
- allow for key/value variables where the key is an ENTT_ID_TYPE
- improves multi-stomp
* range based registry::remove and some others?
* add examples (and credits) from @alanjfs :)
* static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...>
* ENTT_NAMED_TYPE -> ENTT_EXPORT and add also ENTT_EXPORT_WITH_NAME
@@ -34,4 +33,5 @@
- and so on (I'm lazy) :)
* named types: almost-stable index optimization for direct access to pools, no more linear searches
- can implicitly generate types for meta benefit from a similar approach?
* registry::each to iterate all components of an entity
* multi component registry::remove and some others?

View File

@@ -42,6 +42,10 @@ namespace entt {
*/
template<typename Entity>
class basic_registry {
/*! @brief Registries are friend with one another. */
template<typename>
friend class basic_registry;
using context_family = family<struct internal_registry_context_family>;
using component_family = family<struct internal_registry_component_family>;
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
@@ -1542,6 +1546,13 @@ public:
* lists. An excluded type will never be copied.
*
* @warning
* Stomping entities between registries with different types of identifiers
* without a component list is allowed only if the target registry already
* contains the required pools.<br/>
* An assertion will abort the execution at runtime in debug mode in case a
* pool is missing.
*
* @warning
* Attempting to copy components that aren't copyable results in unexpected
* behaviors.<br/>
* A static assertion will abort the compilation when the components
@@ -1555,22 +1566,33 @@ public:
* invalid entities.
*
* @tparam Component Types of components to copy.
* @tparam Entt A valid entity type (see entt_traits for more details).
* @tparam Exclude Types of components not to be copied.
* @param dst A valid entity identifier to copy to.
* @param src A valid entity identifier to be copied.
* @param other The registry that owns the source entity.
*/
template<typename... Component, typename... Exclude>
void stomp(const entity_type dst, const entity_type src, const basic_registry &other, exclude_t<Exclude...> = {}) {
template<typename... Component, typename Entt, typename... Exclude>
void stomp(const entity_type dst, const Entt src, const basic_registry<Entt> &other, exclude_t<Exclude...> = {}) {
if constexpr(sizeof...(Component) == 0) {
for(auto pos = other.pools.size(); pos; --pos) {
if(const auto &pdata = other.pools[pos-1]; pdata.set && ((pdata.runtime_type != to_integer(type<Exclude>())) && ...) && pdata.pool->has(src)) {
pdata.set(*this, dst, pdata.get(*pdata.pool, src));
if constexpr(std::is_same_v<entity_type, Entt>) {
pdata.set(*this, dst, pdata.get(*pdata.pool, src));
} else {
if(const auto ctype = pdata.runtime_type; ctype < pools.size() && pools[ctype].pool && pools[ctype].runtime_type == ctype) {
pools[ctype].set(*this, dst, pdata.get(*pdata.pool, src));
} else {
const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&curr) { return curr.pool && curr.runtime_type == ctype; });
ENTT_ASSERT(it != pools.cend());
it->set(*this, dst, pdata.get(*pdata.pool, src));
}
}
}
}
} else {
static_assert(sizeof...(Exclude) == 0 && std::conjunction_v<std::is_copy_constructible<Component>...>);
(assign_or_replace<Component>(dst, other.get<Component>(src)), ...);
(assign_or_replace<Component>(dst, other.template get<Component>(src)), ...);
}
}

View File

@@ -6,9 +6,11 @@
#include <cstdint>
#include <type_traits>
#include <gtest/gtest.h>
#include <entt/core/type_traits.hpp>
#include <entt/entity/registry.hpp>
#include <entt/entity/entity.hpp>
ENTT_OPAQUE_TYPE(opaque, std::uint64_t);
ENTT_NAMED_TYPE(int);
struct empty_type {};
@@ -1500,6 +1502,27 @@ TEST(Registry, StompMoveOnlyComponent) {
ASSERT_FALSE(registry.has<std::unique_ptr<int>>(entity));
}
TEST(Registry, StompBetweenRegistriesWithDifferentIdentifiers) {
entt::basic_registry<opaque> source;
entt::registry destination;
const auto entity = source.create();
const auto other = destination.create();
source.assign<char>(entity, 'c');
source.assign<double>(entity, 0.);
source.assign<int>(entity, 42);
destination.prepare<int>();
destination.prepare<char>();
destination.stomp(other, entity, source, entt::exclude<double>);
ASSERT_TRUE((destination.has<char, int>(other)));
ASSERT_FALSE(destination.has<double>(other));
ASSERT_EQ(destination.get<char>(other), 'c');
ASSERT_EQ(destination.get<int>(other), 42);
}
TEST(Registry, GetOrAssign) {
entt::registry registry;
const auto entity = registry.create();