فهرست منبع

deprecated prototype/documented registry::stomp

Michele Caini 6 سال پیش
والد
کامیت
0499a6c6f9
3فایلهای تغییر یافته به همراه64 افزوده شده و 85 حذف شده
  1. 51 77
      docs/md/entity.md
  2. 5 0
      src/entt/entity/prototype.hpp
  3. 8 8
      src/entt/entity/registry.hpp

+ 51 - 77
docs/md/entity.md

@@ -18,12 +18,12 @@
   * [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)
   * [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)
-  * [Prototype](#prototype)
   * [The actor class](#the-actor-class)
   * [Helpers](#helpers)
     * [Dependency function](#dependency-function)
@@ -627,6 +627,56 @@ In fact, there are two functions that respond to slightly different needs:
   In this case, instances of `movement` are arranged in memory so that cache
   misses are minimized when the two components are iterated together.
 
+As a side note, when groups are involved, the sorting functions are applied
+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
+
+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
+the background, possibly on a separate thread, without having to keep track of
+which entity belongs to which scene.<br/>
+In fact, with `EnTT` this is even a recommended practice, as the registry is
+nothing more than a container and different optimizations can be applied to
+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).
+
+It opens definitely the doors to a lot of interesting features. Below is a
+brief, yet incomplete list of some of them:
+
+* 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 much less error prone than jumping in the code to
+  update all the snippets copied and pasted around to initialize entities and
+  components.
+
+* 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.
+
+* 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.
+
+* 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.
+
+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.
+
 ## Snapshot: complete vs continuous
 
 The `registry` class offers basic support to serialization.<br/>
@@ -866,82 +916,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.
 
-## Prototype
-
-A prototype defines a type of an application in terms of its parts. They can be
-used to assign components to entities of a registry at once.<br/>
-Roughly speaking, in most cases prototypes can be considered just as templates
-to use to initialize entities according to _concepts_. In fact, users can create
-how many prototypes they want, each one initialized differently from the others.
-
-The following is an example of use of a prototype:
-
-```cpp
-entt::registry registry;
-entt::prototype prototype{registry};
-
-prototype.set<position>(100.f, 100.f);
-prototype.set<velocity>(0.f, 0.f);
-
-// ...
-
-const auto entity = prototype();
-```
-
-To assign and remove components from a prototype, it offers two dedicated member
-functions named `set` and `unset`. The `has` member function can be used to know
-if a given prototype contains one or more components and the `get` member
-function can be used to retrieve the components.
-
-Creating an entity from a prototype is straightforward:
-
-* To create a new entity from scratch and assign it a prototype, this is the way
-  to go:
-
-  ```cpp
-  const auto entity = prototype();
-  ```
-
-  It is equivalent to the following invokation:
-
-  ```cpp
-  const auto entity = prototype.create();
-  ```
-
-* To initialize an already existing entity, users can provide the `operator()`
-  directly with the entity identifier:
-
-  ```cpp
-  prototype(entity);
-  ```
-
-  It is equivalent to the following invokation:
-
-  ```cpp
-  prototype.assign(entity);
-  ```
-
-  Note that existing components aren't overwritten in this case. Only those
-  components that the entity doesn't own yet are copied over. All the other
-  components remain unchanged.
-
-* Finally, to assign or replace all the components for an entity, thus
-  overwriting existing ones:
-
-  ```cpp
-  prototype.assign_or_replace(entity);
-  ```
-
-In the examples above, the prototype uses its underlying registry to create
-entities and components both for its purposes and when it's cloned. To use a
-different repository to clone a prototype, all the member functions accept also
-a reference to a valid registry as a first argument.
-
-Prototypes are a very useful tool that can save a lot of typing sometimes.
-Furthermore, the codebase may be easier to maintain, since updating a prototype
-is much less error prone than jumping around in the codebase to update all the
-snippets copied and pasted around to initialize entities and components.
-
 ## The actor class
 
 The `actor` class is designed for those who don't feel immediately comfortable

+ 5 - 0
src/entt/entity/prototype.hpp

@@ -19,6 +19,11 @@ namespace entt {
 /**
  * @brief Prototype container for _concepts_.
  *
+ * @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.
+ *
  * 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
  * users would otherwise define through a series of component assignments to

+ 8 - 8
src/entt/entity/registry.hpp

@@ -205,7 +205,7 @@ class basic_registry {
         std::unique_ptr<sparse_set<Entity>> pool;
         void(* remove)(sparse_set<Entity> &, basic_registry &, const Entity);
         std::unique_ptr<sparse_set<Entity>>(* clone)(const sparse_set<Entity> &);
-        void(* accommodate)(const sparse_set<Entity> &, const Entity, registry &, const Entity);
+        void(* stomp)(const sparse_set<Entity> &, const Entity, registry &, const Entity);
         ENTT_ID_TYPE runtime_type;
     };
 
@@ -295,12 +295,12 @@ class basic_registry {
                     return std::make_unique<pool_type<Component>>(static_cast<const pool_type<Component> &>(cpool));
                 };
 
-                pdata->accommodate = [](const sparse_set<Entity> &cpool, const Entity from, registry &other, const Entity to) {
+                pdata->stomp = [](const sparse_set<Entity> &cpool, const Entity from, registry &other, const Entity to) {
                     other.assign_or_replace<Component>(to, static_cast<const pool_type<Component> &>(cpool).get(from));
                 };
             } else {
                 pdata->clone = nullptr;
-                pdata->accommodate = nullptr;
+                pdata->stomp = nullptr;
             }
         }
 
@@ -1496,7 +1496,7 @@ public:
                 auto &curr = other.pools[pos-1];
                 curr.remove = pdata.remove;
                 curr.clone = pdata.clone;
-                curr.accommodate = pdata.accommodate;
+                curr.stomp = pdata.stomp;
                 curr.pool = pdata.clone ? pdata.clone(*pdata.pool) : nullptr;
                 curr.runtime_type = pdata.runtime_type;
             }
@@ -1546,20 +1546,20 @@ public:
      * @param to A valid entity identifier to copy to.
      */
     template<typename... Component, typename... Exclude>
-    void clone(const Entity from, registry &other, const Entity to, exclude_t<Exclude...> = {}) {
+    void stomp(const Entity from, registry &other, const Entity to, exclude_t<Exclude...> = {}) {
         static_assert(std::conjunction_v<std::is_copy_constructible<Component>...>);
         ENTT_ASSERT(valid(from) && other.valid(to));
 
         for(auto pos = pools.size(); pos; --pos) {
             const auto &pdata = pools[pos-1];
-            ENTT_ASSERT(!sizeof...(Component) || !pdata.pool || pdata->accommodate);
+            ENTT_ASSERT(!sizeof...(Component) || !pdata.pool || pdata->stomp);
 
-            if(pdata.pool && pdata.accommodate
+            if(pdata.pool && pdata.stomp
                     && (!sizeof...(Component) || ... || (pdata.runtime_type == to_integer(type<Component>())))
                     && !((pdata.runtime_type == to_integer(type<Exclude>())) || ...)
                     && pdata.pool->has(from))
             {
-                pdata.accommodate(*pdata.pool, from, other, to);
+                pdata.stomp(*pdata.pool, from, other, to);
             }
         }
     }