Selaa lähdekoodia

rollback on signals, no need for these changes

Michele Caini 7 vuotta sitten
vanhempi
commit
d02636e370
5 muutettua tiedostoa jossa 56 lisäystä ja 101 poistoa
  1. 7 5
      TODO
  2. 10 16
      docs/md/entity.md
  3. 25 60
      src/entt/entity/registry.hpp
  4. 4 4
      test/entt/entity/helper.cpp
  5. 10 16
      test/entt/entity/registry.cpp

+ 7 - 5
TODO

@@ -22,8 +22,10 @@
 * review sparse set to allow customization (mix pack in the spec, base is position only)
   - non-owning groups can iterate pages and skip empty ones, this should mitigate the lack of the packed array
 * review 64 bit id: user defined area + dedicated member on the registry to set it
-* events on replace, so that one can track updated components
-  - introduce ENTT_REPLACE_ONLY mode
-  - define basic reactive systems (track entities to which component is attached, track entities from which component is removed, and so on)
-  - define systems as composable mixins (initializazion, reactive, update, whatever) with flexible auto-detected arguments (registry, views, etc)
-  - from Tommaso on discord view<Health, Transform>().where<Health>([](h) {h > 5}).where<Transform>([](t) {t.inside(aabb)});
+* add NIO to the EnTT in Action list (link to my CV/LinkedIN)
+
+* reactive systems
+  - add exclusion lists to views (part of signature in this case)
+  - add entt::opt for optional components both to views and groups
+  - add try_get both to views and groups (for optional components)
+  - setup support for reactive systems, something like: registry.reactive(entt:get<A...>, entt::opt<B...>, entt::exclude<C...>)

+ 10 - 16
docs/md/entity.md

@@ -313,34 +313,31 @@ the component owned by an entity if any, a null pointer otherwise.
 
 Because of how the registry works internally, it stores a couple of signal
 handlers for each pool in order to notify some of its data structures on the
-construction and destruction of components. Moreover, it offers also a signal
-handler to listen for changes on components.<br/>
+construction and destruction of components.<br/>
 These signal handlers are also exposed and made available to users. These are
 the basic bricks to build fancy things like dependencies and reactive systems.
 
 To get a sink to be used to connect and disconnect listeners so as to be
-notified on the creation of a component, use the `on_assign` member function:
+notified on the creation of a component, use the `construction` member function:
 
 ```cpp
 // connects a free function
-registry.on_assign<position>().connect<&my_free_function>();
+registry.construction<position>().connect<&my_free_function>();
 
 // connects a member function
-registry.on_assign<position>().connect<&my_class::member>(&instance);
+registry.construction<position>().connect<&my_class::member>(&instance);
 
 // disconnects a free function
-registry.on_assign<position>().disconnect<&my_free_function>();
+registry.construction<position>().disconnect<&my_free_function>();
 
 // disconnects a member function
-registry.on_assign<position>().disconnect<&my_class::member>(&instance);
+registry.construction<position>().disconnect<&my_class::member>(&instance);
 ```
 
-The `on_replace` member function returns instead a sink object to which to
-connect listeners that are triggered when components are explicitly replaced.
-To be notified when components are destroyed, use the `on_remove` member
+To be notified when components are destroyed, use the `destruction` member
 function instead.
 
-The function type of a listener is the same in all cases and should be
+The function type of a listener is the same in both the cases and should be
 equivalent to:
 
 ```cpp
@@ -355,7 +352,6 @@ In other terms, a listener is provided with the registry that triggered the
 notification and the entity affected by the change. Note also that:
 
 * Listeners are invoked **after** components have been assigned to entities.
-* Listeners are invoked **after** components have been replaced for entities.
 * Listeners are invoked **before** components have been removed from entities.
 * The order of invocation of the listeners isn't guaranteed in any case.
 
@@ -364,8 +360,6 @@ particular:
 
 * Connecting and disconnecting other functions from within the body of a
   listener should be avoided. It can lead to undefined behavior in some cases.
-* Replacing components from within the body of a listener that observes changes
-  on entities should be avoided. Intuitively, it could trigger an infinite loop.
 * Assigning and removing components from within the body of a listener that
   observes the destruction of instances of a given type should be avoided. It
   can lead to undefined behavior in some cases. This type of listeners is
@@ -784,7 +778,7 @@ The following adds components `a_type` and `another_type` whenever `my_type` is
 assigned to an entity:
 
 ```cpp
-entt::connnect<a_type, another_type>(registry.on_assign<my_type>());
+entt::connnect<a_type, another_type>(registry.construction<my_type>());
 ```
 
 A component is assigned to an entity and thus default initialized only in case
@@ -793,7 +787,7 @@ 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_assign<my_type>());
+entt::disconnect<a_type, another_type>(registry.construction<my_type>());
 ```
 
 ### Tags

+ 25 - 60
src/entt/entity/registry.hpp

@@ -68,7 +68,7 @@ class basic_registry {
         template<typename... Args>
         Component & construct(Entity entt, Args &&... args) {
             auto &component = sparse_set<Entity, Component>::construct(entt, std::forward<Args>(args)...);
-            on_assign.publish(*owner, entt);
+            construction.publish(*owner, entt);
             return component;
         }
 
@@ -76,9 +76,9 @@ class basic_registry {
         Component * batch(It first, It last) {
             auto *component = sparse_set<Entity, Component>::batch(first, last);
 
-            if(!on_assign.empty()) {
+            if(!construction.empty()) {
                 std::for_each(first, last, [this](const auto entt) {
-                    on_assign.publish(*owner, entt);
+                    construction.publish(*owner, entt);
                 });
             }
 
@@ -86,21 +86,12 @@ class basic_registry {
         }
 
         void destroy(Entity entt) override {
-            on_destroy.publish(*owner, entt);
+            destruction.publish(*owner, entt);
             sparse_set<Entity, Component>::destroy(entt);
         }
 
-        template<typename... Args>
-        Component & replace(const Entity entt, Args &&... args) {
-            auto &component = sparse_set<Entity, Component>::get(entt);
-            component = std::decay_t<Component>{std::forward<Args>(args)...};
-            on_replace.publish(*owner, entt);
-            return component;
-        }
-
-        signal_type on_assign;
-        signal_type on_destroy;
-        signal_type on_replace;
+        signal_type construction;
+        signal_type destruction;
         basic_registry *owner;
     };
 
@@ -864,7 +855,7 @@ public:
      */
     template<typename Component, typename... Args>
     Component & replace(const entity_type entity, Args &&... args) {
-        return assure<Component>()->replace(entity, std::forward<Args>(args)...);
+        return pool<Component>()->get(entity) = Component{std::forward<Args>(args)...};
     }
 
     /**
@@ -896,9 +887,10 @@ public:
     template<typename Component, typename... Args>
     Component & assign_or_replace(const entity_type entity, Args &&... args) {
         auto *cpool = assure<Component>();
+        auto *component = cpool->try_get(entity);
 
-        return cpool->has(entity)
-                ? cpool->replace(entity, std::forward<Args>(args)...)
+        return component
+                ? (*component = Component{std::forward<Args>(args)...})
                 : cpool->construct(entity, std::forward<Args>(args)...);
     }
 
@@ -926,8 +918,8 @@ public:
      * @return A temporary sink object.
      */
     template<typename Component>
-    sink_type on_assign() ENTT_NOEXCEPT {
-        return assure<Component>()->on_assign.sink();
+    sink_type construction() ENTT_NOEXCEPT {
+        return assure<Component>()->construction.sink();
     }
 
     /**
@@ -954,35 +946,8 @@ public:
      * @return A temporary sink object.
      */
     template<typename Component>
-    sink_type on_remove() ENTT_NOEXCEPT {
-        return assure<Component>()->on_destroy.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 explicitly replaced.
-     *
-     * The function type for a listener is equivalent to:
-     * @code{.cpp}
-     * void(registry<Entity> &, Entity);
-     * @endcode
-     *
-     * Listeners are invoked **after** 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 component is replaced.
-     *
-     * @sa sink
-     *
-     * @tparam Component Type of component of which to get the sink.
-     * @return A temporary sink object.
-     */
-    template<typename Component>
-    sink_type on_replace() ENTT_NOEXCEPT {
-        return assure<Component>()->on_replace.sink();
+    sink_type destruction() ENTT_NOEXCEPT {
+        return assure<Component>()->destruction.sink();
     }
 
     /**
@@ -1115,7 +1080,7 @@ public:
      */
     template<typename Component>
     void reset() {
-        if(auto *cpool = assure<Component>(); cpool->on_destroy.empty()) {
+        if(auto *cpool = assure<Component>(); cpool->destruction.empty()) {
             // no group set, otherwise the signal wouldn't be empty
             cpool->reset();
         } else {
@@ -1336,11 +1301,11 @@ public:
                 auto *curr = static_cast<group_type *>(gdata.data.get());
                 const auto cpools = std::make_tuple(assure<Get>()..., assure<Exclude>()...);
 
-                (std::get<pool_type<Get> *>(cpools)->on_destroy.sink().template connect<&group_type::destroy_if>(curr), ...);
-                (std::get<pool_type<Get> *>(cpools)->on_assign.sink().template connect<&group_type::template construct_if<0>>(curr), ...);
+                (std::get<pool_type<Get> *>(cpools)->destruction.sink().template connect<&group_type::destroy_if>(curr), ...);
+                (std::get<pool_type<Get> *>(cpools)->construction.sink().template connect<&group_type::template construct_if<0>>(curr), ...);
 
-                (std::get<pool_type<Exclude> *>(cpools)->on_destroy.sink().template connect<&group_type::template construct_if<1>>(curr), ...);
-                (std::get<pool_type<Exclude> *>(cpools)->on_assign.sink().template connect<&group_type::destroy_if>(curr), ...);
+                (std::get<pool_type<Exclude> *>(cpools)->destruction.sink().template connect<&group_type::template construct_if<1>>(curr), ...);
+                (std::get<pool_type<Exclude> *>(cpools)->construction.sink().template connect<&group_type::destroy_if>(curr), ...);
 
                 for(const auto entity: view<Get...>()) {
                     if(!(has<Exclude>(entity) || ...)) {
@@ -1374,14 +1339,14 @@ public:
                 auto *curr = static_cast<group_type *>(gdata.data.get());
                 const auto cpools = std::make_tuple(assure<Owned>()..., assure<Get>()..., assure<Exclude>()...);
 
-                (std::get<pool_type<Owned> *>(cpools)->on_assign.sink().template connect<&group_type::template induce_if<0>>(curr), ...);
-                (std::get<pool_type<Owned> *>(cpools)->on_destroy.sink().template connect<&group_type::discard_if>(curr), ...);
+                (std::get<pool_type<Owned> *>(cpools)->construction.sink().template connect<&group_type::template induce_if<0>>(curr), ...);
+                (std::get<pool_type<Owned> *>(cpools)->destruction.sink().template connect<&group_type::discard_if>(curr), ...);
 
-                (std::get<pool_type<Get> *>(cpools)->on_assign.sink().template connect<&group_type::template induce_if<0>>(curr), ...);
-                (std::get<pool_type<Get> *>(cpools)->on_destroy.sink().template connect<&group_type::discard_if>(curr), ...);
+                (std::get<pool_type<Get> *>(cpools)->construction.sink().template connect<&group_type::template induce_if<0>>(curr), ...);
+                (std::get<pool_type<Get> *>(cpools)->destruction.sink().template connect<&group_type::discard_if>(curr), ...);
 
-                (std::get<pool_type<Exclude> *>(cpools)->on_destroy.sink().template connect<&group_type::template induce_if<1>>(curr), ...);
-                (std::get<pool_type<Exclude> *>(cpools)->on_assign.sink().template connect<&group_type::discard_if>(curr), ...);
+                (std::get<pool_type<Exclude> *>(cpools)->destruction.sink().template connect<&group_type::template induce_if<1>>(curr), ...);
+                (std::get<pool_type<Exclude> *>(cpools)->construction.sink().template connect<&group_type::discard_if>(curr), ...);
 
                 const auto *cpool = std::min({ static_cast<sparse_set<entity_type> *>(std::get<pool_type<Owned> *>(cpools))... }, [](const auto *lhs, const auto *rhs) {
                     return lhs->size() < rhs->size();

+ 4 - 4
test/entt/entity/helper.cpp

@@ -25,7 +25,7 @@ TEST(Helper, AsGroup) {
 TEST(Helper, Dependency) {
     entt::registry registry;
     const auto entity = registry.create();
-    entt::connect<double, float>(registry.on_assign<int>());
+    entt::connect<double, float>(registry.construction<int>());
 
     ASSERT_FALSE(registry.has<double>(entity));
     ASSERT_FALSE(registry.has<float>(entity));
@@ -61,7 +61,7 @@ TEST(Helper, Dependency) {
     registry.remove<int>(entity);
     registry.remove<double>(entity);
     registry.remove<float>(entity);
-    entt::disconnect<double, float>(registry.on_assign<int>());
+    entt::disconnect<double, float>(registry.construction<int>());
     registry.assign<int>(entity);
 
     ASSERT_FALSE(registry.has<double>(entity));
@@ -70,8 +70,8 @@ TEST(Helper, Dependency) {
 
 TEST(Dependency, MultipleListenersOnTheSameType) {
     entt::registry registry;
-    entt::connect<double>(registry.on_assign<int>());
-    entt::connect<char>(registry.on_assign<int>());
+    entt::connect<double>(registry.construction<int>());
+    entt::connect<char>(registry.construction<int>());
 
     const auto entity = registry.create();
     registry.assign<int>(entity);

+ 10 - 16
test/entt/entity/registry.cpp

@@ -854,9 +854,8 @@ TEST(Registry, Signals) {
     entt::registry registry;
     listener listener;
 
-    registry.on_assign<int>().connect<&listener::incr<int>>(&listener);
-    registry.on_remove<int>().connect<&listener::decr<int>>(&listener);
-    registry.on_replace<int>().connect<&listener::incr<int>>(&listener);
+    registry.construction<int>().connect<&listener::incr<int>>(&listener);
+    registry.destruction<int>().connect<&listener::decr<int>>(&listener);
 
     auto e0 = registry.create();
     auto e1 = registry.create();
@@ -872,20 +871,20 @@ TEST(Registry, Signals) {
     ASSERT_EQ(listener.counter, 1);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_remove<int>().disconnect<&listener::decr<int>>(&listener);
+    registry.destruction<int>().disconnect<&listener::decr<int>>(&listener);
     registry.remove<int>(e1);
 
     ASSERT_EQ(listener.counter, 1);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_assign<int>().disconnect<&listener::incr<int>>(&listener);
+    registry.construction<int>().disconnect<&listener::incr<int>>(&listener);
     registry.assign<int>(e1);
 
     ASSERT_EQ(listener.counter, 1);
     ASSERT_EQ(listener.last, e0);
 
-    registry.on_assign<int>().connect<&listener::incr<int>>(&listener);
-    registry.on_remove<int>().connect<&listener::decr<int>>(&listener);
+    registry.construction<int>().connect<&listener::incr<int>>(&listener);
+    registry.destruction<int>().connect<&listener::decr<int>>(&listener);
     registry.assign<int>(e0);
     registry.reset<int>(e1);
 
@@ -912,12 +911,7 @@ TEST(Registry, Signals) {
 
     registry.assign_or_replace<int>(e0);
 
-    ASSERT_EQ(listener.counter, 2);
-    ASSERT_EQ(listener.last, e0);
-
-    registry.replace<int>(e0);
-
-    ASSERT_EQ(listener.counter, 3);
+    ASSERT_EQ(listener.counter, 1);
     ASSERT_EQ(listener.last, e0);
 }
 
@@ -1063,7 +1057,7 @@ TEST(Registry, CreateManyEntitiesWithComponentsAtOnceWithListener) {
     entt::entity entities[3];
     listener listener;
 
-    registry.on_assign<int>().connect<&listener::incr<int>>(&listener);
+    registry.construction<int>().connect<&listener::incr<int>>(&listener);
     registry.create<int, char>(std::begin(entities), std::end(entities));
 
     ASSERT_EQ(listener.counter, 3);
@@ -1240,8 +1234,8 @@ TEST(Registry, Clone) {
     ASSERT_NE(e1, entity);
     ASSERT_EQ(registry.entity(e1), registry.entity(entity));
 
-    registry.on_assign<char>().connect<&listener::incr<char>>(&listener);
-    registry.on_remove<char>().connect<&listener::decr<char>>(&listener);
+    registry.construction<char>().connect<&listener::incr<char>>(&listener);
+    registry.destruction<char>().connect<&listener::decr<char>>(&listener);
     registry.assign<char>(entity, 'e');
     registry.assign<char>(e0, '0');
     registry.remove<char>(e0);