registry: updated signatures for callbacks, deprecated dependency
This commit is contained in:
4
TODO
4
TODO
@@ -19,6 +19,7 @@
|
||||
* allow to "merge" registries easily
|
||||
* allow for custom stomp functions
|
||||
* deprecate/replace snapshot
|
||||
* remove dependency
|
||||
* remove prototype
|
||||
|
||||
TODO
|
||||
@@ -27,6 +28,3 @@ TODO
|
||||
* make meta work across boundaries
|
||||
- inline variables are fine here, only the head represents a problem
|
||||
- we should always resolve by looking into the list of types when working across boundaries, no direct resolve
|
||||
* signals: entity/registry/component instead of registry/entity/component
|
||||
- dependency becomes a short circuit on the registry
|
||||
- deprecate dependency
|
||||
|
||||
@@ -18,18 +18,18 @@
|
||||
* [Runtime components](#runtime-components)
|
||||
* [A journey through a plugin](#a-journey-through-a-plugin)
|
||||
* [Sorting: is it possible?](#sorting-is-it-possible)
|
||||
* [Multiple registries to the rescue](#multiple-registries-to-the-rescue)
|
||||
* [Helpers](#helpers)
|
||||
* [Null entity](#null-entity)
|
||||
* [Multiple registries](#multiple-registries)
|
||||
* [Dependencies](#dependencies)
|
||||
* [Tags](#tags)
|
||||
* [Actor](#actor)
|
||||
* [Context variables](#context-variables)
|
||||
* [Snapshot: complete vs continuous](#snapshot-complete-vs-continuous)
|
||||
* [Snapshot loader](#snapshot-loader)
|
||||
* [Continuous loader](#continuous-loader)
|
||||
* [Archives](#archives)
|
||||
* [One example to rule them all](#one-example-to-rule-them-all)
|
||||
* [The actor class](#the-actor-class)
|
||||
* [Helpers](#helpers)
|
||||
* [Dependency function](#dependency-function)
|
||||
* [Tags](#tags)
|
||||
* [Null entity](#null-entity)
|
||||
* [Context variables](#context-variables)
|
||||
* [Views and Groups](#views-and-groups)
|
||||
* [Views](#views)
|
||||
* [Runtime views](#runtime-views)
|
||||
@@ -365,7 +365,7 @@ The function type of a listener for the construction signal should be equivalent
|
||||
to the following:
|
||||
|
||||
```cpp
|
||||
void(entt::registry &, entt::entity, Component &);
|
||||
void(entt::entity, entt::registry &, Component &);
|
||||
```
|
||||
|
||||
Where `Component` is intuitively the type of component of interest. In other
|
||||
@@ -377,7 +377,7 @@ signature of which is the same of that of the construction signal. The one of
|
||||
the destruction signal is also similar, except for the `Component` parameter:
|
||||
|
||||
```cpp
|
||||
void(entt::registry &, entt::entity);
|
||||
void(entt::entity, entt::registry &);
|
||||
```
|
||||
|
||||
This is mainly due to performance reasons. While the component is made available
|
||||
@@ -632,7 +632,41 @@ separately to the elements that are part of the group and to those that are not,
|
||||
effectively generating two partitions, both of which can be ordered
|
||||
independently of each other.
|
||||
|
||||
## Multiple registries to the rescue
|
||||
## Helpers
|
||||
|
||||
The so called _helpers_ are small classes and functions mainly designed to offer
|
||||
built-in support for the most basic functionalities.<br/>
|
||||
The list of helpers will grow longer as time passes and new ideas come out.
|
||||
|
||||
### Null entity
|
||||
|
||||
In `EnTT`, there exists a sort of _null entity_ made available to users that is
|
||||
accessible via the `entt::null` variable.<br/>
|
||||
The library guarantees that the following expression always returns false:
|
||||
|
||||
```cpp
|
||||
registry.valid(entt::null);
|
||||
```
|
||||
|
||||
In other terms, a registry will reject the null entity in all cases because it
|
||||
isn't considered valid. It means that the null entity cannot own components for
|
||||
obvious reasons.<br/>
|
||||
The type of the null entity is internal and should not be used for any purpose
|
||||
other than defining the null entity itself. However, there exist implicit
|
||||
conversions from the null entity to identifiers of any allowed type:
|
||||
|
||||
```cpp
|
||||
entt::entity null = entt::null;
|
||||
```
|
||||
|
||||
Similarly, the null entity can be compared to any other identifier:
|
||||
|
||||
```cpp
|
||||
const auto entity = registry.create();
|
||||
const bool null = (entity == entt::null);
|
||||
```
|
||||
|
||||
### Multiple registries
|
||||
|
||||
The use of multiple registries is quite common. Examples of use are the
|
||||
separation of the UI from the simulation or the loading of different scenes in
|
||||
@@ -645,36 +679,109 @@ different containers.
|
||||
Once there are multiple registries available, however, a method is needed to
|
||||
transfer information from one container to another and this results in the
|
||||
`stomp` member function of the `registry` class.<br/>
|
||||
This function allows to take an entity from a registry and copy it over another
|
||||
entity in another registry (or even in place, actually making a local copy).
|
||||
This function allows to take one or more entities from a registry and use them
|
||||
to _stomp_ other entities in another registry (or even the same, actually making
|
||||
local copies).<br/>
|
||||
It opens definitely the doors to a lot of interesting features like migrating
|
||||
entities between registries, prototypes, shadow registry, prefabs, shared
|
||||
components without an explicit owner and copy-on-write policies among the other
|
||||
things.
|
||||
|
||||
It opens definitely the doors to a lot of interesting features. Below is a
|
||||
brief, yet incomplete list of some of them:
|
||||
### Dependencies
|
||||
|
||||
* Prototypes or templates for high level _concepts_ to use to spawn new entities
|
||||
when needed or to _apply_ a given set of components to an existing
|
||||
entity.<br/>
|
||||
Put aside the fact that having the prototypes separated from the simulation is
|
||||
useful in many cases, they make also the codebase easier to maintain, since
|
||||
updating a template is less error prone than jumping in the code to update all
|
||||
the snippets copied and pasted around to initialize entities and components.
|
||||
The `registry` class is designed to create short circuits between its functions
|
||||
within certain limits. This allows to easily define dependencies between
|
||||
different operations.<br/>
|
||||
For example, the following adds (or replaces) the component `a_type` whenever
|
||||
`my_type` is assigned to an entity:
|
||||
|
||||
* Literally _move_ entities from one registry to another (that is a copy
|
||||
followed by a destroy), which can be useful for solving problems such as the
|
||||
migration of entities between different scenes without loss of information.
|
||||
```cpp
|
||||
registry.on_construct<my_type>().connect<&entt::registry::assign_or_replace<a_type>>(registry);
|
||||
```
|
||||
|
||||
* Even prefabs, shared instances without explicit owner and copy-on-write
|
||||
policies among other things are easily achievable in this way and with the
|
||||
_right_ types in use for the components.
|
||||
Similarly, the code shown below removes `a_type` from an entity whenever
|
||||
`my_type` is assigned to it:
|
||||
|
||||
* Remove entities that are distant or not visible so as to reduce the processing
|
||||
time, moving them to a _cold_ registry from which they can be easily resumed
|
||||
at any time.
|
||||
```cpp
|
||||
registry.on_construct<my_type>().connect<&entt::registry::reset<a_type>>(registry);
|
||||
```
|
||||
|
||||
And so on. There are many things that become possible by combining multiple
|
||||
containers but none is really useful without the right means to move entities
|
||||
and components between registries.<br/>
|
||||
Therefore, this seemed a good reason to implement such a feature.
|
||||
A dependency can also be easily broken as follows:
|
||||
|
||||
```cpp
|
||||
registry.on_construct<my_type>().disconnect<&entt::registry::assign_or_replace<a_type>>(registry);
|
||||
```
|
||||
|
||||
There are many other types of dependencies besides those shown above. In
|
||||
general, all functions that accept an entity as the first argument are good
|
||||
candidates for this purpose.
|
||||
|
||||
### Tags
|
||||
|
||||
There's nothing magical about the way tags can be assigned to entities while
|
||||
avoiding a performance hit at runtime. Nonetheless, the syntax can be annoying
|
||||
and that's why a more user-friendly shortcut is provided to do it.<br/>
|
||||
This shortcut is the alias template `entt::tag`.
|
||||
|
||||
If used in combination with hashed strings, it helps to use tags where types
|
||||
would be required otherwise. As an example:
|
||||
|
||||
```cpp
|
||||
registry.assign<entt::tag<"enemy"_hs>>(entity);
|
||||
```
|
||||
|
||||
### Actor
|
||||
|
||||
The `actor` class is designed for those who don't feel immediately comfortable
|
||||
working with components or for those who are migrating a project and want to
|
||||
approach it one step at a time.
|
||||
|
||||
This class acts as a thin wrapper for an entity and for all its components. It's
|
||||
constructed with a registry to be used behind the scenes and is in charge of the
|
||||
destruction of the entity when it goes out of the scope.<br/>
|
||||
An actor offers all the functionalities required to work with components, such
|
||||
as the `assign` and` remove` member functions, but also `has`,` get`, `try_get`
|
||||
and so on.
|
||||
|
||||
My advice isn't to use the `actor` class to hide entities and components behind
|
||||
a more object-oriented interface. Instead, users should rely on it only where
|
||||
strictly necessary. In all other cases, it's highly advisable to become familiar
|
||||
with the model of `EnTT` and work directly with the registry, the views and the
|
||||
groups, rather than with a tool that could introduce a performance degradation.
|
||||
|
||||
### Context variables
|
||||
|
||||
It is often convenient to assign context variables to a registry, so as to make
|
||||
it the only _source of truth_ of an application.<br/>
|
||||
This is possible by means of a member function named `set` to use to create a
|
||||
context variable from a given type. Later on, either `ctx` or `try_ctx` can be
|
||||
used to retrieve the newly created instance and `unset` is there to literally
|
||||
reset it if needed.
|
||||
|
||||
Example of use:
|
||||
|
||||
```cpp
|
||||
// creates a new context variable initialized with the given values
|
||||
registry.set<my_type>(42, 'c');
|
||||
|
||||
// gets the context variable
|
||||
const auto &var = registry.ctx<my_type>();
|
||||
|
||||
// if in doubts, probe the registry to avoid assertions in case of errors
|
||||
if(auto *ptr = registry.try_ctx<my_type>(); ptr) {
|
||||
// uses the context variable associated with the registry, if any
|
||||
}
|
||||
|
||||
// unsets the context variable
|
||||
registry.unset<my_type>();
|
||||
```
|
||||
|
||||
The type of a context variable must be such that it's default constructible and
|
||||
can be moved. The `set` member function either creates a new instance of the
|
||||
context variable or overwrites an already existing one if any. The `try_ctx`
|
||||
member function returns a pointer to the context variable if it exists,
|
||||
otherwise it returns a null pointer. This fits well with the `if` statement with
|
||||
initializer.
|
||||
|
||||
## Snapshot: complete vs continuous
|
||||
|
||||
@@ -915,128 +1022,6 @@ the best way to do it. However, feel free to use it at your own risk.
|
||||
The basic idea is to store everything in a group of queues in memory, then bring
|
||||
everything back to the registry with different loaders.
|
||||
|
||||
## The actor class
|
||||
|
||||
The `actor` class is designed for those who don't feel immediately comfortable
|
||||
working with components or for those who are migrating a project and want to
|
||||
approach it one step at a time.
|
||||
|
||||
This class acts as a thin wrapper for an entity and for all its components. It's
|
||||
constructed with a registry to be used behind the scenes and is in charge of the
|
||||
destruction of the entity when it goes out of the scope.<br/>
|
||||
An actor offers all the functionalities required to work with components, such
|
||||
as the `assign` and` remove` member functions, but also `has`,` get`, `try_get`
|
||||
and so on.
|
||||
|
||||
My advice isn't to use the `actor` class to hide entities and components behind
|
||||
a more object-oriented interface. Instead, users should rely on it only where
|
||||
strictly necessary. In all other cases, it's highly advisable to become familiar
|
||||
with the model of `EnTT` and work directly with the registry, the views and the
|
||||
groups, rather than with a tool that could introduce a performance degradation.
|
||||
|
||||
## Helpers
|
||||
|
||||
The so called _helpers_ are small classes and functions mainly designed to offer
|
||||
built-in support for the most basic functionalities.<br/>
|
||||
The list of helpers will grow longer as time passes and new ideas come out.
|
||||
|
||||
### Dependency function
|
||||
|
||||
A _dependency function_ is a predefined listener, actually a function template
|
||||
to use to automatically assign components to an entity when a type has a
|
||||
dependency on some other types.<br/>
|
||||
The following adds components `a_type` and `another_type` whenever `my_type` is
|
||||
assigned to an entity:
|
||||
|
||||
```cpp
|
||||
entt::connect<a_type, another_type>(registry.on_construct<my_type>());
|
||||
```
|
||||
|
||||
A component is assigned to an entity and thus default initialized only in case
|
||||
the entity itself hasn't it yet. It means that already existent components won't
|
||||
be overriden.<br/>
|
||||
A dependency can easily be broken by means of the following function template:
|
||||
|
||||
```cpp
|
||||
entt::disconnect<a_type, another_type>(registry.on_construct<my_type>());
|
||||
```
|
||||
|
||||
### Tags
|
||||
|
||||
There's nothing magical about the way tags can be assigned to entities while
|
||||
avoiding a performance hit at runtime. Nonetheless, the syntax can be annoying
|
||||
and that's why a more user-friendly shortcut is provided to do it.<br/>
|
||||
This shortcut is the alias template `entt::tag`.
|
||||
|
||||
If used in combination with hashed strings, it helps to use tags where types
|
||||
would be required otherwise. As an example:
|
||||
|
||||
```cpp
|
||||
registry.assign<entt::tag<"enemy"_hs>>(entity);
|
||||
```
|
||||
|
||||
## Null entity
|
||||
|
||||
In `EnTT`, there exists a sort of _null entity_ made available to users that is
|
||||
accessible via the `entt::null` variable.<br/>
|
||||
The library guarantees that the following expression always returns false:
|
||||
|
||||
```cpp
|
||||
registry.valid(entt::null);
|
||||
```
|
||||
|
||||
In other terms, a registry will reject the null entity in all cases because it
|
||||
isn't considered valid. It means that the null entity cannot own components for
|
||||
obvious reasons.<br/>
|
||||
The type of the null entity is internal and should not be used for any purpose
|
||||
other than defining the null entity itself. However, there exist implicit
|
||||
conversions from the null entity to identifiers of any allowed type:
|
||||
|
||||
```cpp
|
||||
entt::entity null = entt::null;
|
||||
```
|
||||
|
||||
Similarly, the null entity can be compared to any other identifier:
|
||||
|
||||
```cpp
|
||||
const auto entity = registry.create();
|
||||
const bool null = (entity == entt::null);
|
||||
```
|
||||
|
||||
## Context variables
|
||||
|
||||
It is often convenient to assign context variables to a registry, so as to make
|
||||
it the only _source of truth_ of an application.<br/>
|
||||
This is possible by means of a member function named `set` to use to create a
|
||||
context variable from a given type. Later on, either `ctx` or `try_ctx` can be
|
||||
used to retrieve the newly created instance and `unset` is there to literally
|
||||
reset it if needed.
|
||||
|
||||
Example of use:
|
||||
|
||||
```cpp
|
||||
// creates a new context variable initialized with the given values
|
||||
registry.set<my_type>(42, 'c');
|
||||
|
||||
// gets the context variable
|
||||
const auto &var = registry.ctx<my_type>();
|
||||
|
||||
// if in doubts, probe the registry to avoid assertions in case of errors
|
||||
if(auto *ptr = registry.try_ctx<my_type>(); ptr) {
|
||||
// uses the context variable associated with the registry, if any
|
||||
}
|
||||
|
||||
// unsets the context variable
|
||||
registry.unset<my_type>();
|
||||
```
|
||||
|
||||
The type of a context variable must be such that it's default constructible and
|
||||
can be moved. The `set` member function either creates a new instance of the
|
||||
context variable or overwrites an already existing one if any. The `try_ctx`
|
||||
member function returns a pointer to the context variable if it exists,
|
||||
otherwise it returns a null pointer. This fits well with the `if` statement with
|
||||
initializer.
|
||||
|
||||
# Views and Groups
|
||||
|
||||
First of all, it is worth answering an obvious question: why views and
|
||||
|
||||
@@ -112,6 +112,11 @@ as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>
|
||||
/**
|
||||
* @brief Dependency function prototype.
|
||||
*
|
||||
* @deprecated
|
||||
* This function will be wiped out in a future version of the library.<br/>
|
||||
* Use shortcuts and cross links between registries to achieve the same result
|
||||
* in a more idiomatic way.
|
||||
*
|
||||
* A _dependency function_ is a built-in listener to use to automatically assign
|
||||
* components to an entity when a type has a dependency on some other types.
|
||||
*
|
||||
@@ -120,11 +125,11 @@ as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Dependency Types of components to assign to an entity if triggered.
|
||||
* @param reg A valid reference to a registry.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param reg A valid reference to a registry.
|
||||
*/
|
||||
template<typename Entity, typename... Dependency>
|
||||
void dependency(basic_registry<Entity> ®, const Entity entt) {
|
||||
void dependency(const Entity entt, basic_registry<Entity> ®) {
|
||||
((reg.template has<Dependency>(entt) ? void() : (reg.template assign<Dependency>(entt), void())), ...);
|
||||
}
|
||||
|
||||
@@ -132,6 +137,11 @@ void dependency(basic_registry<Entity> ®, const Entity entt) {
|
||||
/**
|
||||
* @brief Connects a dependency function to the given sink.
|
||||
*
|
||||
* @deprecated
|
||||
* This function will be wiped out in a future version of the library.<br/>
|
||||
* Use shortcuts and cross links between registries to achieve the same result
|
||||
* in a more idiomatic way.
|
||||
*
|
||||
* A _dependency function_ is a built-in listener to use to automatically assign
|
||||
* components to an entity when a type has a dependency on some other types.
|
||||
*
|
||||
@@ -148,7 +158,7 @@ void dependency(basic_registry<Entity> ®, const Entity entt) {
|
||||
* @param sink A sink object properly initialized.
|
||||
*/
|
||||
template<typename... Dependency, typename Component, typename Entity>
|
||||
void connect(sink<void(basic_registry<Entity> &, const Entity, Component &)> sink) {
|
||||
void connect(sink<void(const Entity, basic_registry<Entity> &, Component &)> sink) {
|
||||
constexpr auto function = &dependency<Entity, Dependency...>;
|
||||
sink.template connect<function>();
|
||||
}
|
||||
@@ -157,6 +167,11 @@ void connect(sink<void(basic_registry<Entity> &, const Entity, Component &)> sin
|
||||
/**
|
||||
* @brief Disconnects a dependency function from the given sink.
|
||||
*
|
||||
* @deprecated
|
||||
* This function will be wiped out in a future version of the library.<br/>
|
||||
* Use shortcuts and cross links between registries to achieve the same result
|
||||
* in a more idiomatic way.
|
||||
*
|
||||
* A _dependency function_ is a built-in listener to use to automatically assign
|
||||
* components to an entity when a type has a dependency on some other types.
|
||||
*
|
||||
@@ -173,7 +188,7 @@ void connect(sink<void(basic_registry<Entity> &, const Entity, Component &)> sin
|
||||
* @param sink A sink object properly initialized.
|
||||
*/
|
||||
template<typename... Dependency, typename Component, typename Entity>
|
||||
void disconnect(sink<void(basic_registry<Entity> &, const Entity, Component &)> sink) {
|
||||
void disconnect(sink<void(const Entity, basic_registry<Entity> &, Component &)> sink) {
|
||||
constexpr auto function = &dependency<Entity, Dependency...>;
|
||||
sink.template disconnect<function>();
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ class basic_observer {
|
||||
template<typename... Reject, typename... Require, typename AnyOf>
|
||||
struct matcher_handler<matcher<matcher<type_list<Reject...>, type_list<Require...>>, AnyOf>> {
|
||||
template<std::size_t Index>
|
||||
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> ®, const Entity entt) {
|
||||
static void maybe_valid_if(basic_observer &obs, const Entity entt, const basic_registry<Entity> ®) {
|
||||
if(reg.template has<Require...>(entt) && !(reg.template has<Reject>(entt) || ...)) {
|
||||
auto *comp = obs.view.try_get(entt);
|
||||
(comp ? *comp : obs.view.construct(entt)) |= (1 << Index);
|
||||
@@ -181,7 +181,7 @@ class basic_observer {
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
|
||||
static void discard_if(basic_observer &obs, const Entity entt) {
|
||||
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
|
||||
obs.view.destroy(entt);
|
||||
}
|
||||
@@ -206,7 +206,7 @@ class basic_observer {
|
||||
template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
|
||||
struct matcher_handler<matcher<matcher<type_list<Reject...>, type_list<Require...>>, type_list<NoneOf...>, type_list<AllOf...>>> {
|
||||
template<std::size_t Index>
|
||||
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> ®, const Entity entt) {
|
||||
static void maybe_valid_if(basic_observer &obs, const Entity entt, const basic_registry<Entity> ®) {
|
||||
if(reg.template has<AllOf...>(entt) && !(reg.template has<NoneOf>(entt) || ...)
|
||||
&& reg.template has<Require...>(entt) && !(reg.template has<Reject>(entt) || ...))
|
||||
{
|
||||
@@ -216,7 +216,7 @@ class basic_observer {
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
|
||||
static void discard_if(basic_observer &obs, const Entity entt) {
|
||||
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
|
||||
obs.view.destroy(entt);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace entt {
|
||||
*
|
||||
* @deprecated
|
||||
* This class will be wiped out in a future version of the library.<br/>
|
||||
* Use a shadow registry and the new `registry::stomp` functionality to achieve
|
||||
* the same result in a more idiomatic way.
|
||||
* Use a prototype registry and the new `registry::stomp` functionality to
|
||||
* achieve the same result in a more idiomatic way.
|
||||
*
|
||||
* A prototype is used to define a _concept_ in terms of components.<br/>
|
||||
* Prototypes act as templates for those specific types of an application which
|
||||
|
||||
@@ -76,11 +76,11 @@ class basic_registry {
|
||||
decltype(auto) assign(basic_registry ®istry, const Entity entt, Args &&... args) {
|
||||
if constexpr(std::is_empty_v<Component>) {
|
||||
storage<Entity, Component>::construct(entt);
|
||||
construction.publish(registry, entt, Component{});
|
||||
construction.publish(entt, registry, Component{});
|
||||
return Component{std::forward<Args>(args)...};
|
||||
} else {
|
||||
auto &component = storage<Entity, Component>::construct(entt, std::forward<Args>(args)...);
|
||||
construction.publish(registry, entt, component);
|
||||
construction.publish(entt, registry, component);
|
||||
return component;
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ class basic_registry {
|
||||
|
||||
if(!construction.empty()) {
|
||||
std::for_each(first, last, [this, ®istry](const auto entt) {
|
||||
construction.publish(registry, entt, Component{});
|
||||
construction.publish(entt, registry, Component{});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -102,7 +102,7 @@ class basic_registry {
|
||||
|
||||
if(!construction.empty()) {
|
||||
std::for_each(first, last, [this, ®istry, component](const auto entt) mutable {
|
||||
construction.publish(registry, entt, *(component++));
|
||||
construction.publish(entt, registry, *(component++));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -111,7 +111,7 @@ class basic_registry {
|
||||
}
|
||||
|
||||
void remove(basic_registry ®istry, const Entity entt) {
|
||||
destruction.publish(registry, entt);
|
||||
destruction.publish(entt, registry);
|
||||
storage<Entity, Component>::destroy(entt);
|
||||
}
|
||||
|
||||
@@ -119,20 +119,20 @@ class basic_registry {
|
||||
decltype(auto) replace(basic_registry ®istry, const Entity entt, Args &&... args) {
|
||||
if constexpr(std::is_empty_v<Component>) {
|
||||
ENTT_ASSERT((storage<Entity, Component>::has(entt)));
|
||||
update.publish(registry, entt, Component{});
|
||||
update.publish(entt, registry, Component{});
|
||||
return Component{std::forward<Args>(args)...};
|
||||
} else {
|
||||
Component component{std::forward<Args>(args)...};
|
||||
update.publish(registry, entt, component);
|
||||
update.publish(entt, registry, component);
|
||||
return (storage<Entity, Component>::get(entt) = std::move(component));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using reference_type = std::conditional_t<std::is_empty_v<Component>, const Component &, Component &>;
|
||||
sigh<void(basic_registry &, const Entity, reference_type)> construction{};
|
||||
sigh<void(basic_registry &, const Entity, reference_type)> update{};
|
||||
sigh<void(basic_registry &, const Entity)> destruction{};
|
||||
sigh<void(const Entity, basic_registry &, reference_type)> construction{};
|
||||
sigh<void(const Entity, basic_registry &, reference_type)> update{};
|
||||
sigh<void(const Entity, basic_registry &)> destruction{};
|
||||
};
|
||||
|
||||
template<typename Component>
|
||||
@@ -146,7 +146,7 @@ class basic_registry {
|
||||
std::tuple<pool_type<Get> *..., pool_type<Exclude> *...> cpools{};
|
||||
|
||||
template<typename Component>
|
||||
void maybe_valid_if(const basic_registry &, const Entity entt) {
|
||||
void maybe_valid_if(const Entity entt) {
|
||||
if constexpr(std::disjunction_v<std::is_same<Get, Component>...>) {
|
||||
if(((std::is_same_v<Component, Get> || std::get<pool_type<Get> *>(cpools)->has(entt)) && ...)
|
||||
&& !(std::get<pool_type<Exclude> *>(cpools)->has(entt) || ...))
|
||||
@@ -161,7 +161,7 @@ class basic_registry {
|
||||
}
|
||||
}
|
||||
|
||||
void discard_if(const basic_registry &, const Entity entt) {
|
||||
void discard_if(const Entity entt) {
|
||||
if(this->has(entt)) {
|
||||
this->destroy(entt);
|
||||
}
|
||||
@@ -173,7 +173,7 @@ class basic_registry {
|
||||
std::tuple<pool_type<Owned> *..., pool_type<Get> *..., pool_type<Exclude> *...> cpools{};
|
||||
|
||||
template<typename Component>
|
||||
void maybe_valid_if(const basic_registry &, const Entity entt) {
|
||||
void maybe_valid_if(const Entity entt) {
|
||||
if constexpr(std::disjunction_v<std::is_same<Owned, Component>..., std::is_same<Get, Component>...>) {
|
||||
if(((std::is_same_v<Component, Owned> || std::get<pool_type<Owned> *>(cpools)->has(entt)) && ...)
|
||||
&& ((std::is_same_v<Component, Get> || std::get<pool_type<Get> *>(cpools)->has(entt)) && ...)
|
||||
@@ -193,7 +193,7 @@ class basic_registry {
|
||||
}
|
||||
}
|
||||
|
||||
void discard_if(const basic_registry &, const Entity entt) {
|
||||
void discard_if(const Entity entt) {
|
||||
if(std::get<0>(cpools)->has(entt) && std::get<0>(cpools)->sparse_set<Entity>::get(entt) < this->owned) {
|
||||
const auto pos = --this->owned;
|
||||
(std::get<pool_type<Owned> *>(cpools)->swap(std::get<pool_type<Owned> *>(cpools)->sparse_set<Entity>::get(entt), pos), ...);
|
||||
@@ -906,7 +906,7 @@ public:
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(registry<Entity> &, Entity, Component &);
|
||||
* void(Entity, registry<Entity> &, Component &);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **after** the component has been assigned to the
|
||||
@@ -937,7 +937,7 @@ public:
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(registry<Entity> &, Entity, Component &);
|
||||
* void(Entity, registry<Entity> &, Component &);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **before** the component has been replaced. The
|
||||
@@ -969,7 +969,7 @@ public:
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(registry<Entity> &, Entity);
|
||||
* void(Entity, registry<Entity> &);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **before** the component has been removed from the
|
||||
|
||||
@@ -15,7 +15,7 @@ struct empty_type {};
|
||||
|
||||
struct listener {
|
||||
template<typename Component>
|
||||
void incr(entt::registry ®istry, entt::entity entity, const Component &) {
|
||||
void incr(entt::entity entity, entt::registry ®istry, const Component &) {
|
||||
ASSERT_TRUE(registry.valid(entity));
|
||||
ASSERT_TRUE(registry.has<Component>(entity));
|
||||
last = entity;
|
||||
@@ -23,7 +23,7 @@ struct listener {
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
void decr(entt::registry ®istry, entt::entity entity) {
|
||||
void decr(entt::entity entity, entt::registry ®istry) {
|
||||
ASSERT_TRUE(registry.valid(entity));
|
||||
ASSERT_TRUE(registry.has<Component>(entity));
|
||||
last = entity;
|
||||
@@ -1524,3 +1524,32 @@ TEST(Registry, MoveOnlyComponent) {
|
||||
const auto entity = registry.create();
|
||||
registry.assign<std::unique_ptr<int>>(entity);
|
||||
}
|
||||
|
||||
TEST(Registry, Dependencies) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.on_construct<int>().connect<&entt::registry::assign_or_replace<double>>(registry);
|
||||
registry.on_destroy<int>().connect<&entt::registry::remove<double>>(registry);
|
||||
registry.assign<double>(entity, .3);
|
||||
|
||||
ASSERT_FALSE(registry.has<int>(entity));
|
||||
ASSERT_EQ(registry.get<double>(entity), .3);
|
||||
|
||||
registry.assign<int>(entity);
|
||||
|
||||
ASSERT_TRUE(registry.has<int>(entity));
|
||||
ASSERT_EQ(registry.get<double>(entity), .0);
|
||||
|
||||
registry.remove<int>(entity);
|
||||
|
||||
ASSERT_FALSE(registry.has<int>(entity));
|
||||
ASSERT_FALSE(registry.has<double>(entity));
|
||||
|
||||
registry.on_construct<int>().disconnect<&entt::registry::assign_or_replace<double>>(registry);
|
||||
registry.on_destroy<int>().disconnect<&entt::registry::remove<double>>(registry);
|
||||
registry.assign<int>(entity);
|
||||
|
||||
ASSERT_TRUE(registry.has<int>(entity));
|
||||
ASSERT_FALSE(registry.has<double>(entity));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user