signal on replace

This commit is contained in:
Michele Caini
2019-04-09 08:54:19 +02:00
parent ae927c5600
commit 4292d2ce86
3 changed files with 51 additions and 23 deletions

View File

@@ -348,7 +348,8 @@ registry.construction<position>().disconnect<&my_class::member>(&instance);
```
To be notified when components are destroyed, use the `destruction` member
function instead.
function instead. Finally, the `update` member function will return a sink to
which to connect listeners to observe changes on components.
The function type of a listener for the construction signal should be equivalent
to the following:
@@ -361,8 +362,9 @@ Where `Component` is intuitively the type of component of interest. In other
words, a listener is provided with the registry that triggered the notification
and the entity affected by the change, in addition to the newly created
instance.<br/>
The function type of a listener for the destruction signal is the same, except
for the `Component` parameter:
The function type of a listener to be notified about changes is the same of that
of the construction signal. The one the destruction signal is also similar,
except for the `Component` parameter:
```cpp
void(registry &, entt::entity);
@@ -375,8 +377,13 @@ this case, the registry is made available for the purpose.
Note also that:
* Listeners are invoked **after** components have been assigned to entities.
* Listeners are invoked **before** components have been removed from entities.
* Listeners for the construction signal are invoked **after** components have
been assigned to entities.
* Listeners designed to observe changes are invoked **before** components have
been replaced and therefore before newly created instances have been assigned
to entities.
* Listeners for the destruction signal are invoked **before** components have
been removed from entities.
* The order of invocation of the listeners isn't guaranteed in any case.
There are also some limitations on what a listener can and cannot do. In

View File

@@ -91,14 +91,15 @@ class basic_registry {
template<typename... Args>
Component & replace(const Entity entt, Args &&... args) {
destruction.publish(*owner, entt);
auto &component = sparse_set<Entity, Component>::get(entt);
component = Component{std::forward<Args>(args)...};
construction.publish(*owner, entt, component);
return component;
Component component{std::forward<Args>(args)...};
update.publish(*owner, entt, component);
auto &other = sparse_set<Entity, Component>::get(entt);
std::swap(other, component);
return other;
}
sigh<void(basic_registry &, const Entity, Component &)> construction;
sigh<void(basic_registry &, const Entity, Component &)> update;
sigh<void(basic_registry &, const Entity)> destruction;
basic_registry *owner;
};
@@ -394,12 +395,6 @@ public:
using size_type = typename sparse_set<Entity>::size_type;
/*! @brief Unsigned integer type. */
using component_type = ENTT_ID_TYPE;
/*! @brief Destruction sink type. */
using destruction_sink_type = typename sigh<void(basic_registry &, const Entity)>::sink_type;
/*! @brief Construction sink type for the given component. */
template<typename Component>
using construction_sink_type = typename sigh<void(basic_registry &, const Entity, Component &)>::sink_type;
/*! @brief Default constructor. */
basic_registry() ENTT_NOEXCEPT = default;
@@ -1052,10 +1047,37 @@ public:
* @return A temporary sink object.
*/
template<typename Component>
construction_sink_type<Component> construction() ENTT_NOEXCEPT {
auto construction() ENTT_NOEXCEPT {
return assure<Component>()->construction.sink();
}
/**
* @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 updated.
*
* The function type for a listener is equivalent to:
* @code{.cpp}
* void(registry<Entity> &, Entity, Component &);
* @endcode
*
* Listeners are invoked **before** the component has been replaced. The
* order of invocation of the listeners isn't guaranteed.<br/>
* Note also that the greater the number of listeners, the greater the
* performance hit when a new component is created.
*
* @sa sink
*
* @tparam Component Type of component of which to get the sink.
* @return A temporary sink object.
*/
template<typename Component>
auto update() ENTT_NOEXCEPT {
return assure<Component>()->update.sink();
}
/**
* @brief Returns a sink object for the given component.
*
@@ -1080,7 +1102,7 @@ public:
* @return A temporary sink object.
*/
template<typename Component>
destruction_sink_type destruction() ENTT_NOEXCEPT {
auto destruction() ENTT_NOEXCEPT {
return assure<Component>()->destruction.sink();
}

View File

@@ -912,19 +912,18 @@ TEST(Registry, Signals) {
registry.destruction<int>().disconnect<&listener::decr<int>>(&listener);
registry.assign_or_replace<int>(e0);
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.counter, 1);
ASSERT_EQ(listener.last, e0);
registry.construction<int>().disconnect<&listener::incr<int>>(&listener);
registry.destruction<int>().connect<&listener::decr<int>>(&listener);
registry.update<int>().connect<&listener::incr<int>>(&listener);
registry.assign_or_replace<int>(e0);
ASSERT_EQ(listener.counter, 1);
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, e0);
registry.replace<int>(e0);
ASSERT_EQ(listener.counter, 0);
ASSERT_EQ(listener.counter, 3);
ASSERT_EQ(listener.last, e0);
}