Michele Caini 7 лет назад
Родитель
Сommit
4292d2ce86
3 измененных файлов с 51 добавлено и 23 удалено
  1. 12 5
      docs/md/entity.md
  2. 35 13
      src/entt/entity/registry.hpp
  3. 4 5
      test/entt/entity/registry.cpp

+ 12 - 5
docs/md/entity.md

@@ -348,7 +348,8 @@ registry.construction<position>().disconnect<&my_class::member>(&instance);
 ```
 ```
 
 
 To be notified when components are destroyed, use the `destruction` member
 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
 The function type of a listener for the construction signal should be equivalent
 to the following:
 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
 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
 and the entity affected by the change, in addition to the newly created
 instance.<br/>
 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
 ```cpp
 void(registry &, entt::entity);
 void(registry &, entt::entity);
@@ -375,8 +377,13 @@ this case, the registry is made available for the purpose.
 
 
 Note also that:
 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.
 * 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
 There are also some limitations on what a listener can and cannot do. In

+ 35 - 13
src/entt/entity/registry.hpp

@@ -91,14 +91,15 @@ class basic_registry {
 
 
         template<typename... Args>
         template<typename... Args>
         Component & replace(const Entity entt, Args &&... 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 &)> construction;
+        sigh<void(basic_registry &, const Entity, Component &)> update;
         sigh<void(basic_registry &, const Entity)> destruction;
         sigh<void(basic_registry &, const Entity)> destruction;
         basic_registry *owner;
         basic_registry *owner;
     };
     };
@@ -394,12 +395,6 @@ public:
     using size_type = typename sparse_set<Entity>::size_type;
     using size_type = typename sparse_set<Entity>::size_type;
     /*! @brief Unsigned integer type. */
     /*! @brief Unsigned integer type. */
     using component_type = ENTT_ID_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. */
     /*! @brief Default constructor. */
     basic_registry() ENTT_NOEXCEPT = default;
     basic_registry() ENTT_NOEXCEPT = default;
@@ -1052,10 +1047,37 @@ public:
      * @return A temporary sink object.
      * @return A temporary sink object.
      */
      */
     template<typename Component>
     template<typename Component>
-    construction_sink_type<Component> construction() ENTT_NOEXCEPT {
+    auto construction() ENTT_NOEXCEPT {
         return assure<Component>()->construction.sink();
         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.
      * @brief Returns a sink object for the given component.
      *
      *
@@ -1080,7 +1102,7 @@ public:
      * @return A temporary sink object.
      * @return A temporary sink object.
      */
      */
     template<typename Component>
     template<typename Component>
-    destruction_sink_type destruction() ENTT_NOEXCEPT {
+    auto destruction() ENTT_NOEXCEPT {
         return assure<Component>()->destruction.sink();
         return assure<Component>()->destruction.sink();
     }
     }
 
 

+ 4 - 5
test/entt/entity/registry.cpp

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