doc: updated documentation about signals from a registry
This commit is contained in:
@@ -364,7 +364,7 @@ registry.on_construct<position>().disconnect<&my_free_function>();
|
||||
registry.on_construct<position>().disconnect<&my_class::member>(instance);
|
||||
```
|
||||
|
||||
To be notified when components are destroyed, use the `on_destroy` member
|
||||
To be notified when a component is destroyed, use the `on_destroy` member
|
||||
function instead. Finally, the `on_update` member function will return a sink
|
||||
to which to connect listeners to observe changes.<br/>
|
||||
In the last case, given the way C++ works, it's also necessary to use specific
|
||||
@@ -375,12 +375,9 @@ attached to `on_update` will only be invoked following a call to `replace` or
|
||||
The function type of a listener should be equivalent to the following:
|
||||
|
||||
```cpp
|
||||
void(entt::registry &, entt::entity);
|
||||
void(entt::entity);
|
||||
```
|
||||
|
||||
In all cases, listeners are provided with the registry that triggered the
|
||||
notification and the involved entity.
|
||||
|
||||
Note also that:
|
||||
|
||||
* Listeners for the construction signals are invoked **after** components have
|
||||
@@ -633,25 +630,25 @@ that isn't associated with the given registry can result in undefined behavior.
|
||||
|
||||
The `registry` class is designed to be able to create short circuits between its
|
||||
functions. This simplifies the definition of _dependencies_ between different
|
||||
operations.<br/>
|
||||
operations and registries.<br/>
|
||||
For example, the following adds (or replaces) the component `a_type` whenever
|
||||
`my_type` is assigned to an entity:
|
||||
|
||||
```cpp
|
||||
registry.on_construct<my_type>().connect<&entt::registry::emplace_or_replace<a_type>>();
|
||||
registry.on_construct<my_type>().connect<&entt::registry::emplace_or_replace<a_type>>(registry);
|
||||
```
|
||||
|
||||
Similarly, the code shown below removes `a_type` from an entity whenever
|
||||
`my_type` is assigned to it:
|
||||
|
||||
```cpp
|
||||
registry.on_construct<my_type>().connect<&entt::registry::remove<a_type>>();
|
||||
registry.on_construct<my_type>().connect<&entt::registry::remove<a_type>>(registry);
|
||||
```
|
||||
|
||||
A dependency can also be easily broken as follows:
|
||||
|
||||
```cpp
|
||||
registry.on_construct<my_type>().disconnect<&entt::registry::emplace_or_replace<a_type>>();
|
||||
registry.on_construct<my_type>().disconnect<&entt::registry::emplace_or_replace<a_type>>(registry);
|
||||
```
|
||||
|
||||
There are many other types of dependencies. In general, most of the functions
|
||||
@@ -666,11 +663,13 @@ _extend_ their classes and this may not always be possible.<br/>
|
||||
The `invoke` helper allows to _propagate_ the signal in these cases:
|
||||
|
||||
```cpp
|
||||
registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
|
||||
registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>(registry);
|
||||
```
|
||||
|
||||
All it does is pick up the _right_ component for the received entity and invoke
|
||||
the requested method, passing on the arguments if necessary.
|
||||
the requested method, passing on the arguments if necessary.<br/>
|
||||
The registry is also supplied by the invoker directly to the function invoked as
|
||||
the first argument.
|
||||
|
||||
### Handle
|
||||
|
||||
|
||||
@@ -14,35 +14,126 @@
|
||||
namespace entt {
|
||||
|
||||
|
||||
template<typename Entity, typename Component>
|
||||
struct default_pool final: storage<Entity, Component> {
|
||||
static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Invalid component type");
|
||||
/**
|
||||
* @brief Default pool implementation.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Type Type of objects assigned to the entities.
|
||||
*/
|
||||
template<typename Entity, typename Type>
|
||||
struct default_pool final: storage<Entity, Type> {
|
||||
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Invalid object type");
|
||||
|
||||
/*! @brief Type of the objects associated with the entities. */
|
||||
using object_type = Type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever a new instance is created and assigned to an entity.<br/>
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(Entity);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **after** the object has been assigned to the
|
||||
* entity.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_construct() ENTT_NOEXCEPT {
|
||||
return sink{construction};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object for the given type.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance is explicitly updated.<br/>
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(Entity);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **after** the object has been updated.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_update() ENTT_NOEXCEPT {
|
||||
return sink{update};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object for the given type.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance is removed from an entity and thus destroyed.<br/>
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(Entity);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **before** the object has been removed from the
|
||||
* entity.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_destroy() ENTT_NOEXCEPT {
|
||||
return sink{destruction};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns an entity to a pool.
|
||||
*
|
||||
* A new object is created and initialized with the arguments provided (the
|
||||
* object type must have a proper constructor or be of aggregate type). Then
|
||||
* the instance is assigned to the given entity.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid entity or to assign an entity that already
|
||||
* belongs to the pool results in undefined behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode in case of
|
||||
* invalid entity or if the entity already belongs to the pool.
|
||||
*
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param entity A valid entity identifier.
|
||||
* @param args Parameters to use to initialize the object.
|
||||
* @return A reference to the newly created object.
|
||||
*/
|
||||
template<typename... Args>
|
||||
decltype(auto) emplace(const Entity entt, Args &&... args) {
|
||||
storage<entity_type, Component>::emplace(entt, std::forward<Args>(args)...);
|
||||
decltype(auto) emplace(const entity_type entt, Args &&... args) {
|
||||
storage<entity_type, Type>::emplace(entt, std::forward<Args>(args)...);
|
||||
construction.publish(entt);
|
||||
|
||||
if constexpr(!is_eto_eligible_v<Component>) {
|
||||
if constexpr(!is_eto_eligible_v<object_type>) {
|
||||
return this->get(entt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns multiple entities to a pool.
|
||||
*
|
||||
* @sa emplace
|
||||
*
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @param value An instance of the type to assign.
|
||||
*/
|
||||
template<typename It, typename... Args>
|
||||
void insert(It first, It last, Args &&... args) {
|
||||
storage<entity_type, Component>::insert(first, last, std::forward<Args>(args)...);
|
||||
storage<entity_type, object_type>::insert(first, last, std::forward<Args>(args)...);
|
||||
|
||||
if(!construction.empty()) {
|
||||
for(; first != last; ++first) {
|
||||
@@ -51,11 +142,31 @@ struct default_pool final: storage<Entity, Component> {
|
||||
}
|
||||
}
|
||||
|
||||
void erase(const Entity entt) override {
|
||||
/**
|
||||
* @brief Removes an entity from a pool.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid entity or to remove an entity that doesn't
|
||||
* belong to the pool results in undefined behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode in case of
|
||||
* invalid entity or if the entity doesn't belong to the pool.
|
||||
*
|
||||
* @param entity A valid entity identifier.
|
||||
*/
|
||||
void erase(const entity_type entt) override {
|
||||
destruction.publish(entt);
|
||||
storage<entity_type, Component>::erase(entt);
|
||||
storage<entity_type, object_type>::erase(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes multiple entities from a pool.
|
||||
*
|
||||
* @see remove
|
||||
*
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
*/
|
||||
template<typename It>
|
||||
void erase(It first, It last) {
|
||||
if(std::distance(first, last) == std::distance(this->begin(), this->end())) {
|
||||
@@ -73,9 +184,34 @@ struct default_pool final: storage<Entity, Component> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Patches the given instance for an entity.
|
||||
*
|
||||
* The signature of the functions should be equivalent to the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(Type &);
|
||||
* @endcode
|
||||
*
|
||||
* @note
|
||||
* Empty types aren't explicitly instantiated and therefore they are never
|
||||
* returned. However, this function can be used to trigger an update signal
|
||||
* for them.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid entity or to patch an object of an entity
|
||||
* that doesn't belong to the pool results in undefined behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode in case of
|
||||
* invalid entity or if the entity doesn't belong to the pool.
|
||||
*
|
||||
* @tparam Func Types of the function objects to invoke.
|
||||
* @param entity A valid entity identifier.
|
||||
* @param func Valid function objects.
|
||||
* @return A reference to the patched instance.
|
||||
*/
|
||||
template<typename... Func>
|
||||
decltype(auto) patch(const Entity entt, [[maybe_unused]] Func &&... func) {
|
||||
if constexpr(is_eto_eligible_v<Component>) {
|
||||
decltype(auto) patch(const entity_type entt, [[maybe_unused]] Func &&... func) {
|
||||
if constexpr(is_eto_eligible_v<object_type>) {
|
||||
update.publish(entt);
|
||||
} else {
|
||||
(std::forward<Func>(func)(this->get(entt)), ...);
|
||||
@@ -84,14 +220,32 @@ struct default_pool final: storage<Entity, Component> {
|
||||
}
|
||||
}
|
||||
|
||||
decltype(auto) replace(const Entity entt, Component component) {
|
||||
return patch(entt, [&component](auto &&curr) { curr = std::move(component); });
|
||||
/**
|
||||
* @brief Replaces the object associated with an entity in a pool.
|
||||
*
|
||||
* A new object is created and initialized with the arguments provided (the
|
||||
* object type must have a proper constructor or be of aggregate type). Then
|
||||
* the instance is assigned to the given entity.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid entity or to replace an object of an entity
|
||||
* that doesn't belong to the pool results in undefined behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode in case of
|
||||
* invalid entity or if the entity doesn't belong to the pool.
|
||||
*
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param entity A valid entity identifier.
|
||||
* @param args Parameters to use to initialize the object.
|
||||
* @return A reference to the object being replaced.
|
||||
*/
|
||||
decltype(auto) replace(const entity_type entt, object_type instance) {
|
||||
return patch(entt, [&instance](auto &&curr) { curr = std::move(instance); });
|
||||
}
|
||||
|
||||
private:
|
||||
sigh<void(const Entity)> construction{};
|
||||
sigh<void(const Entity)> destruction{};
|
||||
sigh<void(const Entity)> update{};
|
||||
sigh<void(const entity_type)> construction{};
|
||||
sigh<void(const entity_type)> destruction{};
|
||||
sigh<void(const entity_type)> update{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1015,15 +1015,13 @@ public:
|
||||
/**
|
||||
* @brief Returns a sink object for the given component.
|
||||
*
|
||||
* A sink is an opaque object used to connect listeners to components.<br/>
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever a new instance of the given component is created and assigned to
|
||||
* an entity.
|
||||
*
|
||||
* an entity.<br/>
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(registry<Entity> &, Entity);
|
||||
* void(Entity);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **after** the component has been assigned to the
|
||||
@@ -1042,14 +1040,12 @@ public:
|
||||
/**
|
||||
* @brief Returns a sink object for the given component.
|
||||
*
|
||||
* A sink is an opaque object used to connect listeners to components.<br/>
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance of the given component is explicitly updated.
|
||||
*
|
||||
* whenever an instance of the given component is explicitly updated.<br/>
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(registry<Entity> &, Entity);
|
||||
* void(Entity);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **after** the component has been updated.
|
||||
@@ -1067,15 +1063,13 @@ public:
|
||||
/**
|
||||
* @brief Returns a sink object for the given component.
|
||||
*
|
||||
* A sink is an opaque object used to connect listeners to components.<br/>
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance of the given component is removed from an entity and
|
||||
* thus destroyed.
|
||||
*
|
||||
* thus destroyed.<br/>
|
||||
* The function type for a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(registry<Entity> &, Entity);
|
||||
* void(Entity);
|
||||
* @endcode
|
||||
*
|
||||
* Listeners are invoked **before** the component has been removed from the
|
||||
|
||||
Reference in New Issue
Block a user