|
|
@@ -12,7 +12,7 @@
|
|
|
* [Pay per use](#pay-per-use)
|
|
|
* [All or nothing](#all-or-nothing)
|
|
|
* [Vademecum](#vademecum)
|
|
|
-* [Pools](#pools)
|
|
|
+* [Storage](#storage)
|
|
|
* [The Registry, the Entity and the Component](#the-registry-the-entity-and-the-component)
|
|
|
* [Observe changes](#observe-changes)
|
|
|
* [Listeners disconnection](#listeners-disconnection)
|
|
|
@@ -66,8 +66,8 @@
|
|
|
|
|
|
# Introduction
|
|
|
|
|
|
-`EnTT` is a header-only, tiny and easy to use entity-component system (and much
|
|
|
-more) written in modern C++.<br/>
|
|
|
+`EnTT` offers a header-only, tiny and easy to use entity-component system module
|
|
|
+written in modern C++.<br/>
|
|
|
The entity-component-system (also known as _ECS_) is an architectural pattern
|
|
|
used mostly in game development.
|
|
|
|
|
|
@@ -75,8 +75,8 @@ used mostly in game development.
|
|
|
|
|
|
## Type-less and bitset-free
|
|
|
|
|
|
-`EnTT` offers a sparse set based model that doesn't require users to specify the
|
|
|
-set of components neither at compile-time nor at runtime.<br/>
|
|
|
+The library implements a sparse set based model that doesn't require users to
|
|
|
+specify the set of components neither at compile-time nor at runtime.<br/>
|
|
|
This is why users can instantiate the core class simply like:
|
|
|
|
|
|
```cpp
|
|
|
@@ -94,19 +94,20 @@ When the time comes, just use it and that's all.
|
|
|
|
|
|
## Build your own
|
|
|
|
|
|
-`EnTT` is designed as a container that can be used at any time, just like a
|
|
|
-vector or any other container. It doesn't attempt in any way to take over on the
|
|
|
-user codebase, nor to control its main loop or process scheduling.<br/>
|
|
|
+The ECS module (as well as the rest of the library) is designed as a set of
|
|
|
+containers that are used as needed, just like a vector or any other container.
|
|
|
+It doesn't attempt in any way to take over on the user codebase, nor to control
|
|
|
+its main loop or process scheduling.<br/>
|
|
|
Unlike other more or less well known models, it also makes use of independent
|
|
|
-pools that can be extended via _static mixins_. The built-in signal support is
|
|
|
-an example of this flexible model: defined as a mixin, it's easily disabled if
|
|
|
-not needed. Similarly, the storage class has a specialization that shows how
|
|
|
+pools that are extended via _static mixins_. The built-in signal support is an
|
|
|
+example of this flexible design: defined as a mixin, it's easily disabled if not
|
|
|
+needed. Similarly, the storage class has a specialization that shows how
|
|
|
everything is customizable down to the smallest detail.
|
|
|
|
|
|
## Pay per use
|
|
|
|
|
|
-`EnTT` is entirely designed around the principle that users have to pay only for
|
|
|
-what they want.
|
|
|
+Everything is designed around the principle that users only have to pay for what
|
|
|
+they want.
|
|
|
|
|
|
When it comes to using an entity-component system, the tradeoff is usually
|
|
|
between performance and memory usage. The faster it is, the more memory it uses.
|
|
|
@@ -119,40 +120,30 @@ performance.<br/>
|
|
|
basic data structures and gives users the possibility to pay more for higher
|
|
|
performance where needed.
|
|
|
|
|
|
-So far, this choice has proven to be a good one and I really hope it can be for
|
|
|
-many others besides me.
|
|
|
-
|
|
|
## All or nothing
|
|
|
|
|
|
-`EnTT` is such that a `T**` pointer (or whatever a custom pool returns) is
|
|
|
+As a rule of thumb, a `T **` pointer (or whatever a custom pool returns) is
|
|
|
always available to directly access all the instances of a given component type
|
|
|
`T`.<br/>
|
|
|
-I cannot say whether it will be useful or not to the reader, but it's worth to
|
|
|
-mention it since it's one of the corner stones of this library.
|
|
|
-
|
|
|
-Many of the tools described below give the possibility to get this information
|
|
|
-and have been designed around this need.<br/>
|
|
|
-The rest is experimentation and the desire to invent something new, hoping to
|
|
|
-have succeeded.
|
|
|
+This is one of the corner stones of the library. Many of the tools offered are
|
|
|
+designed around this need and give the possibility to get this information.
|
|
|
|
|
|
# Vademecum
|
|
|
|
|
|
-The registry to store, the views and the groups to iterate. That's all.
|
|
|
-
|
|
|
The `entt::entity` type implements the concept of _entity identifier_. An entity
|
|
|
(the _E_ of an _ECS_) is an opaque element to use as-is. Inspecting it isn't
|
|
|
recommended since its format can change in future.<br/>
|
|
|
Components (the _C_ of an _ECS_) are of any type, without any constraints, not
|
|
|
even that of being movable. No need to register them nor their types.<br/>
|
|
|
-Systems (the _S_ of an _ECS_) can be plain functions, functors, lambdas and so
|
|
|
-on. It's not required to announce them in any case and have no requirements.
|
|
|
+Systems (the _S_ of an _ECS_) are plain functions, functors, lambdas and so on.
|
|
|
+It's not required to announce them in any case and have no requirements.
|
|
|
|
|
|
The next sections go into detail on how to use the entity-component system part
|
|
|
of the `EnTT` library.<br/>
|
|
|
-The project is composed of many other classes in addition to those described
|
|
|
-below. For more details, please refer to the inline documentation.
|
|
|
+This module is likely larger than what is described below. For more details,
|
|
|
+please refer to the inline documentation.
|
|
|
|
|
|
-# Pools
|
|
|
+# Storage
|
|
|
|
|
|
Pools of components are a sort of _specialized version_ of a sparse set. Each
|
|
|
pool contains all the instances of a single component type and all the entities
|
|
|
@@ -166,10 +157,10 @@ packed and maximize performance, unless pointer stability is enabled.
|
|
|
# The Registry, the Entity and the Component
|
|
|
|
|
|
A registry stores and manages entities (or better, identifiers) and pools.<br/>
|
|
|
-The class template `basic_registry` lets users decide what's the preferred type
|
|
|
-to represent an entity. Because `std::uint32_t` is large enough for almost all
|
|
|
-the cases, there also exists the enum class `entt::entity` that _wraps_ it and
|
|
|
-the alias `entt::registry` for `entt::basic_registry<entt::entity>`.
|
|
|
+The class template `basic_registry` lets users decide what the preferred type to
|
|
|
+represent an entity is. Because `std::uint32_t` is large enough for almost any
|
|
|
+case, there also exists the enum class `entt::entity` that _wraps_ it and the
|
|
|
+alias `entt::registry` for `entt::basic_registry<entt::entity>`.
|
|
|
|
|
|
Entities are represented by _entity identifiers_. An entity identifier contains
|
|
|
information about the entity itself and its version.<br/>
|
|
|
@@ -186,8 +177,8 @@ auto entity = registry.create();
|
|
|
registry.destroy(entity);
|
|
|
```
|
|
|
|
|
|
-The `create` member function also accepts a hint and has an overload that gets
|
|
|
-two iterators and can be used to generate multiple entities at once efficiently.
|
|
|
+The `create` member function also accepts a hint. Moreover, it has an overload
|
|
|
+that gets two iterators to use to generate many entities at once efficiently.
|
|
|
Similarly, the `destroy` member function also works with a range of entities:
|
|
|
|
|
|
```cpp
|
|
|
@@ -196,10 +187,10 @@ auto view = registry.view<a_component, another_component>();
|
|
|
registry.destroy(view.begin(), view.end());
|
|
|
```
|
|
|
|
|
|
-In addition to offering an overload to force the version upon destruction. Note
|
|
|
-that this function removes all components from an entity before releasing its
|
|
|
-identifier. There also exists a _lighter_ alternative that only releases the
|
|
|
-elements without poking in any pool, for use with orphaned entities:
|
|
|
+In addition to offering an overload to force the version upon destruction.<br/>
|
|
|
+This function removes all components from an entity before releasing it. There
|
|
|
+also exists a _lighter_ alternative that doesn't query component pools, for use
|
|
|
+with orphaned entities:
|
|
|
|
|
|
```cpp
|
|
|
// releases an orphaned identifier
|
|
|
@@ -207,12 +198,12 @@ registry.release(entity);
|
|
|
```
|
|
|
|
|
|
As with the `destroy` function, also in this case entity ranges are supported
|
|
|
-and it's possible to force the version during release.
|
|
|
+and it's possible to force a _version_.
|
|
|
|
|
|
In both cases, when an identifier is released, the registry can freely reuse it
|
|
|
internally. In particular, the version of an entity is increased (unless the
|
|
|
overload that forces a version is used instead of the default one).<br/>
|
|
|
-Users can probe an identifier to know the information it carries:
|
|
|
+Users can then _inspect_ the identifiers by means of a registry:
|
|
|
|
|
|
```cpp
|
|
|
// returns true if the entity is still valid, false otherwise
|
|
|
@@ -225,12 +216,10 @@ auto version = registry.version(entity);
|
|
|
auto curr = registry.current(entity);
|
|
|
```
|
|
|
|
|
|
-Components can be assigned to or removed from entities at any time. As for the
|
|
|
-entities, the registry offers a set of functions to use to work with components.
|
|
|
-
|
|
|
+Components are assigned to or removed from entities at any time.<br/>
|
|
|
The `emplace` member function template creates, initializes and assigns to an
|
|
|
entity the given component. It accepts a variable number of arguments to use to
|
|
|
-construct the component itself if present:
|
|
|
+construct the component itself:
|
|
|
|
|
|
```cpp
|
|
|
registry.emplace<position>(entity, 0., 0.);
|
|
|
@@ -244,10 +233,9 @@ vel.dy = 0.;
|
|
|
|
|
|
The default storage _detects_ aggregate types internally and exploits aggregate
|
|
|
initialization when possible.<br/>
|
|
|
-Therefore, it's not strictly necessary to define a constructor for each type, in
|
|
|
-accordance with the rules of the language.
|
|
|
+Therefore, it's not strictly necessary to define a constructor for each type.
|
|
|
|
|
|
-On the other hand, `insert` works with _ranges_ and can be used to:
|
|
|
+The `insert` member function works with _ranges_ and is used to:
|
|
|
|
|
|
* Assign the same component to all entities at once when a type is specified as
|
|
|
a template parameter or an instance is passed as an argument:
|
|
|
@@ -261,7 +249,7 @@ On the other hand, `insert` works with _ranges_ and can be used to:
|
|
|
```
|
|
|
|
|
|
* Assign a set of components to the entities when a range is provided (the
|
|
|
- length of the range of components must be the same of that of entities):
|
|
|
+ length of the range of components **must** be the same of that of entities):
|
|
|
|
|
|
```cpp
|
|
|
// first and last specify the range of entities, instances points to the first element of the range of components
|
|
|
@@ -269,7 +257,7 @@ On the other hand, `insert` works with _ranges_ and can be used to:
|
|
|
```
|
|
|
|
|
|
If an entity already has the given component, the `replace` and `patch` member
|
|
|
-function templates can be used to update it:
|
|
|
+function templates are used to update it:
|
|
|
|
|
|
```cpp
|
|
|
// replaces the component in-place
|
|
|
@@ -286,7 +274,7 @@ When it's unknown whether an entity already owns an instance of a component,
|
|
|
registry.emplace_or_replace<position>(entity, 0., 0.);
|
|
|
```
|
|
|
|
|
|
-This is a slightly faster alternative for the following snippet:
|
|
|
+This is a slightly faster alternative to the following snippet:
|
|
|
|
|
|
```cpp
|
|
|
if(registry.all_of<velocity>(entity)) {
|
|
|
@@ -315,14 +303,14 @@ registry.erase<position>(entity);
|
|
|
```
|
|
|
|
|
|
When in doubt whether the entity owns the component, use the `remove` member
|
|
|
-function instead. It behaves similarly to `erase` but it erases the component
|
|
|
-if and only if it exists, otherwise it returns safely to the caller:
|
|
|
+function instead. It behaves similarly to `erase` but it drops the component if
|
|
|
+and only if it exists, otherwise it returns safely to the caller:
|
|
|
|
|
|
```cpp
|
|
|
registry.remove<position>(entity);
|
|
|
```
|
|
|
|
|
|
-The `clear` member function works similarly and can be used to either:
|
|
|
+The `clear` member function works similarly and is used to either:
|
|
|
|
|
|
* Erases all instances of the given components from the entities that own them:
|
|
|
|
|
|
@@ -336,7 +324,7 @@ The `clear` member function works similarly and can be used to either:
|
|
|
registry.clear();
|
|
|
```
|
|
|
|
|
|
-Finally, references to components can be retrieved simply as:
|
|
|
+Finally, references to components are obtained simply as:
|
|
|
|
|
|
```cpp
|
|
|
const auto &cregistry = registry;
|
|
|
@@ -350,10 +338,8 @@ const auto [cpos, cvel] = cregistry.get<position, velocity>(entity);
|
|
|
auto [pos, vel] = registry.get<position, velocity>(entity);
|
|
|
```
|
|
|
|
|
|
-The `get` member function template gives direct access to the component of an
|
|
|
-entity stored in the underlying data structures of the registry. There exists
|
|
|
-also an alternative member function named `try_get` that returns a pointer to
|
|
|
-the component owned by an entity if any, a null pointer otherwise.
|
|
|
+If the existence of the component isn't certain, `try_get` is the more suitable
|
|
|
+function instead.
|
|
|
|
|
|
## Observe changes
|
|
|
|
|
|
@@ -448,28 +434,28 @@ In order to explain what reactive systems are, this is a slightly revised quote
|
|
|
from the documentation of the library that first introduced this tool,
|
|
|
[Entitas](https://github.com/sschmid/Entitas-CSharp):
|
|
|
|
|
|
->Imagine you have 100 fighting units on the battlefield but only 10 of them
|
|
|
->changed their positions. Instead of using a normal system and updating all 100
|
|
|
->entities depending on the position, you can use a reactive system which will
|
|
|
->only update the 10 changed units. So efficient.
|
|
|
+> Imagine you have 100 fighting units on the battlefield but only 10 of them
|
|
|
+> changed their positions. Instead of using a normal system and updating all 100
|
|
|
+> entities depending on the position, you can use a reactive system which will
|
|
|
+> only update the 10 changed units. So efficient.
|
|
|
|
|
|
-In `EnTT`, this means to iterating over a reduced set of entities and components
|
|
|
-with respect to what would otherwise be returned from a view or a group.<br/>
|
|
|
+In `EnTT`, this means iterating over a reduced set of entities and components
|
|
|
+than what would otherwise be returned from a view or group.<br/>
|
|
|
On these words, however, the similarities with the proposal of `Entitas` also
|
|
|
end. The rules of the language and the design of the library obviously impose
|
|
|
and allow different things.
|
|
|
|
|
|
-An `observer` is initialized with an instance of a registry and a set of rules
|
|
|
+An `observer` is initialized with an instance of a registry and a set of _rules_
|
|
|
that describes what are the entities to intercept. As an example:
|
|
|
|
|
|
```cpp
|
|
|
entt::observer observer{registry, entt::collector.update<sprite>()};
|
|
|
```
|
|
|
|
|
|
-The class is default constructible and can be reconfigured at any time by means
|
|
|
-of the `connect` member function. Moreover, instances can be disconnected from
|
|
|
-the underlying registries through the `disconnect` member function.<br/>
|
|
|
-The `observer` offers also what is needed to query the internal state and to
|
|
|
+The class is default constructible and is reconfigured at any time by means of
|
|
|
+the `connect` member function. Moreover, an observer is disconnected from the
|
|
|
+underlying registry through the `disconnect` member function.<br/>
|
|
|
+The `observer` offers also what is needed to query its _internal state_ and to
|
|
|
know if it's empty or how many entities it contains. Moreover, it can return a
|
|
|
raw pointer to the list of entities it contains.
|
|
|
|
|
|
@@ -505,25 +491,23 @@ At least as long as the `observer` isn't const. This means that the non-const
|
|
|
overload of `each` does also reset the underlying data structure before to
|
|
|
return to the caller, while the const overload does not for obvious reasons.
|
|
|
|
|
|
-The `collector` is a utility aimed to generate a list of `matcher`s (the actual
|
|
|
-rules) to use with an `observer` instead.<br/>
|
|
|
+A `collector` is a utility aimed to generate a list of `matcher`s (the actual
|
|
|
+rules) to use with an `observer`.<br/>
|
|
|
There are two types of `matcher`s:
|
|
|
|
|
|
-* Observing matcher: an observer will return at least all the living entities
|
|
|
- for which one or more of the given components have been updated and not yet
|
|
|
- destroyed.
|
|
|
+* Observing matcher: an observer returns at least the entities for which one or
|
|
|
+ more of the given components have been updated and not yet destroyed.
|
|
|
|
|
|
```cpp
|
|
|
entt::collector.update<sprite>();
|
|
|
```
|
|
|
|
|
|
- _Updated_ in this case means that all listeners attached to `on_update` are
|
|
|
- invoked. In order for this to happen, specific functions such as `patch` must
|
|
|
- be used. Refer to the specific documentation for more details.
|
|
|
+ Where _updated_ means that all listeners attached to `on_update` are invoked.
|
|
|
+ In order for this to happen, specific functions such as `patch` must be used.
|
|
|
+ Refer to the specific documentation for more details.
|
|
|
|
|
|
-* Grouping matcher: an observer will return at least all the living entities
|
|
|
- that would have entered the given group if it existed and that would have
|
|
|
- not yet left it.
|
|
|
+* Grouping matcher: an observer returns at least the entities that would have
|
|
|
+ entered the given group if it existed and that would have not yet left it.
|
|
|
|
|
|
```cpp
|
|
|
entt::collector.group<position, velocity>(entt::exclude<destroyed>);
|
|
|
@@ -537,7 +521,7 @@ have assigned the given components since the last time one asked.<br/>
|
|
|
If an entity already has all the components except one and the missing type is
|
|
|
assigned to it, the entity is intercepted by a grouping matcher.
|
|
|
|
|
|
-In addition, a matcher can be filtered with a `where` clause:
|
|
|
+In addition, matchers support filtering by means of a `where` clause:
|
|
|
|
|
|
```cpp
|
|
|
entt::collector.update<sprite>().where<position>(entt::exclude<velocity>);
|
|
|
@@ -547,9 +531,9 @@ This clause introduces a way to intercept entities if and only if they are
|
|
|
already part of a hypothetical group. If they are not, they aren't returned by
|
|
|
the observer, no matter if they matched the given rule.<br/>
|
|
|
In the example above, whenever the component `sprite` of an entity is updated,
|
|
|
-the observer probes the entity itself to verify that it has at least `position`
|
|
|
-and has not `velocity` before to store it aside. If one of the two conditions of
|
|
|
-the filter isn't respected, the entity is discarded, no matter what.
|
|
|
+the observer checks the entity itself to verify that it has at least `position`
|
|
|
+and has not `velocity`. If one of the two conditions isn't satisfied, the entity
|
|
|
+is discarded, no matter what.
|
|
|
|
|
|
A `where` clause accepts a theoretically unlimited number of types as well as
|
|
|
multiple elements in the exclusion list. Moreover, every matcher can have its
|
|
|
@@ -558,12 +542,11 @@ one.
|
|
|
|
|
|
## Sorting: is it possible?
|
|
|
|
|
|
-Sorting entities and components is possible with `EnTT`. In particular, it uses
|
|
|
-an in-place algorithm that doesn't require memory allocations nor anything else
|
|
|
-and is therefore particularly convenient.<br/>
|
|
|
+Sorting entities and components is possible using an in-place algorithm that
|
|
|
+doesn't require memory allocations and is therefore quite convenient.<br/>
|
|
|
There are two functions that respond to slightly different needs:
|
|
|
|
|
|
-* Components can be sorted either directly:
|
|
|
+* Components are sorted either directly:
|
|
|
|
|
|
```cpp
|
|
|
registry.sort<renderable>([](const auto &lhs, const auto &rhs) {
|
|
|
@@ -580,10 +563,9 @@ There are two functions that respond to slightly different needs:
|
|
|
```
|
|
|
|
|
|
There exists also the possibility to use a custom sort function object for
|
|
|
- when the usage pattern is known. As an example, in case of an almost sorted
|
|
|
- pool, quick sort could be much slower than insertion sort.
|
|
|
+ when the usage pattern is known.
|
|
|
|
|
|
-* Components can be sorted according to the order imposed by another component:
|
|
|
+* Components are sorted according to the order imposed by another component:
|
|
|
|
|
|
```cpp
|
|
|
registry.sort<movement, physics>();
|
|
|
@@ -602,7 +584,7 @@ built-in support for the most basic functionalities.
|
|
|
|
|
|
### Null entity
|
|
|
|
|
|
-The `entt::null` variable models the concept of _null entity_.<br/>
|
|
|
+The `entt::null` variable models the concept of a _null entity_.<br/>
|
|
|
The library guarantees that the following expression always returns false:
|
|
|
|
|
|
```cpp
|
|
|
@@ -619,7 +601,7 @@ conversions from the null entity to identifiers of any allowed type:
|
|
|
entt::entity null = entt::null;
|
|
|
```
|
|
|
|
|
|
-Similarly, the null entity can be compared to any other identifier:
|
|
|
+Similarly, the null entity compares to any other identifier:
|
|
|
|
|
|
```cpp
|
|
|
const auto entity = registry.create();
|
|
|
@@ -631,13 +613,13 @@ identifier and is instead completely transparent to its version.
|
|
|
|
|
|
Be aware that `entt::null` and entity 0 aren't the same thing. Likewise, a zero
|
|
|
initialized entity isn't the same as `entt::null`. Therefore, although
|
|
|
-`entt::entity{}` is in some sense an alias for entity 0, none of them can be
|
|
|
-used to create a null entity.
|
|
|
+`entt::entity{}` is in some sense an alias for entity 0, none of them are used
|
|
|
+to create a null entity.
|
|
|
|
|
|
### Tombstone
|
|
|
|
|
|
Similar to the null entity, the `entt::tombstone` variable models the concept of
|
|
|
-_tombstone_.<br/>
|
|
|
+a _tombstone_.<br/>
|
|
|
Once created, the integral form of the two values is the same, although they
|
|
|
affect different parts of an identifier. In fact, the tombstone only uses the
|
|
|
version part of it and is completely transparent to the entity part.
|
|
|
@@ -662,7 +644,7 @@ exist implicit conversions from a tombstone to identifiers of any allowed type:
|
|
|
entt::entity null = entt::tombstone;
|
|
|
```
|
|
|
|
|
|
-Similarly, the tombstone can be compared to any other identifier:
|
|
|
+Similarly, the tombstone compares to any other identifier:
|
|
|
|
|
|
```cpp
|
|
|
const auto entity = registry.create();
|
|
|
@@ -671,14 +653,13 @@ const bool tombstone = (entity == entt::tombstone);
|
|
|
|
|
|
Be aware that `entt::tombstone` and entity 0 aren't the same thing. Likewise, a
|
|
|
zero initialized entity isn't the same as `entt::tombstone`. Therefore, although
|
|
|
-`entt::entity{}` is in some sense an alias for entity 0, none of them can be
|
|
|
-used to create tombstones.
|
|
|
+`entt::entity{}` is in some sense an alias for entity 0, none of them are used
|
|
|
+to create tombstones.
|
|
|
|
|
|
### To entity
|
|
|
|
|
|
-Sometimes it's useful to get the entity from a component instance.<br/>
|
|
|
-This is what the `entt::to_entity` helper does. It accepts a registry and an
|
|
|
-instance of a component and returns the entity associated with the latter:
|
|
|
+This function accepts a registry and an instance of a component and returns the
|
|
|
+entity associated with the latter:
|
|
|
|
|
|
```cpp
|
|
|
const auto entity = entt::to_entity(registry, position);
|
|
|
@@ -688,9 +669,8 @@ A null entity is returned in case the component doesn't belong to the registry.
|
|
|
|
|
|
### Dependencies
|
|
|
|
|
|
-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/>
|
|
|
+The `registry` class is designed to create short circuits between its member
|
|
|
+functions. This greatly simplifies the definition of a _dependency_.<br/>
|
|
|
For example, the following adds (or replaces) the component `a_type` whenever
|
|
|
`my_type` is assigned to an entity:
|
|
|
|
|
|
@@ -698,29 +678,27 @@ For example, the following adds (or replaces) the component `a_type` whenever
|
|
|
registry.on_construct<my_type>().connect<&entt::registry::emplace_or_replace<a_type>>();
|
|
|
```
|
|
|
|
|
|
-Similarly, the code shown below removes `a_type` from an entity whenever
|
|
|
-`my_type` is assigned to it:
|
|
|
+Similarly, the code 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>>();
|
|
|
```
|
|
|
|
|
|
-A dependency can also be easily broken as follows:
|
|
|
+A dependency is easily _broken_ as follows:
|
|
|
|
|
|
```cpp
|
|
|
registry.on_construct<my_type>().disconnect<&entt::registry::emplace_or_replace<a_type>>();
|
|
|
```
|
|
|
|
|
|
-There are many other types of dependencies. In general, most of the functions
|
|
|
-that accept an entity as the first argument are good candidates for this
|
|
|
+There are many other types of _dependencies_. In general, most of the functions
|
|
|
+that accept an entity as their first argument are good candidates for this
|
|
|
purpose.
|
|
|
|
|
|
### Invoke
|
|
|
|
|
|
-Sometimes it's useful to directly invoke a member function of a component as a
|
|
|
-callback. It's already possible in practice but requires users to _extend_ their
|
|
|
-classes and this may not always be possible.<br/>
|
|
|
-The `invoke` helper allows to _propagate_ the signal in these cases:
|
|
|
+The `invoke` helper allows to _propagate_ a signal to a member function of a
|
|
|
+component without having to _extend_ it:
|
|
|
|
|
|
```cpp
|
|
|
registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
|
|
|
@@ -748,19 +726,16 @@ in the most complex cases.
|
|
|
|
|
|
### Handle
|
|
|
|
|
|
-A handle is a thin wrapper around an entity and a registry. It provides the same
|
|
|
-functions that the registry offers for working with components, such as
|
|
|
-`emplace`, `get`, `patch`, `remove` and so on. The difference being that the
|
|
|
-entity is implicitly passed to the registry.<br/>
|
|
|
+A handle is a thin wrapper around an entity and a registry. It _replicates_ the
|
|
|
+API of a registry by offering functions such as `get` or `emplace`. The
|
|
|
+difference being that the entity is implicitly passed to the registry.<br/>
|
|
|
It's default constructible as an invalid handle that contains a null registry
|
|
|
and a null entity. When it contains a null registry, calling functions that
|
|
|
-delegate execution to the registry will cause an undefined behavior, so it's
|
|
|
-recommended to check the validity of the handle with implicit cast to `bool`
|
|
|
-when in doubt.<br/>
|
|
|
-A handle is also non-owning, meaning that it can be freely copied and moved
|
|
|
-around without affecting its entity (in fact, handles happen to be trivially
|
|
|
-copyable). An implication of this is that mutability becomes part of the
|
|
|
-type.
|
|
|
+delegate execution to the registry causes undefined behavior. It's recommended
|
|
|
+to test for validity with its implicit cast to `bool` if in doubt.<br/>
|
|
|
+A handle is also non-owning, meaning that it's freely copied and moved around
|
|
|
+without affecting its entity (in fact, handles happen to be trivially copyable).
|
|
|
+An implication of this is that mutability becomes part of the type.
|
|
|
|
|
|
There are two aliases that use `entt::entity` as their default entity:
|
|
|
`entt::handle` and `entt::const_handle`.<br/>
|
|
|
@@ -771,12 +746,8 @@ using my_handle = entt::basic_handle<entt::basic_registry<my_identifier>>;
|
|
|
using my_const_handle = entt::basic_handle<const entt::basic_registry<my_identifier>>;
|
|
|
```
|
|
|
|
|
|
-Handles are also implicitly convertible to const handles out of the box but not
|
|
|
-the other way around.<br/>
|
|
|
-A handle stores a non-const pointer to a registry and therefore it can do all
|
|
|
-the things that can be done with a non-const registry. On the other hand, const
|
|
|
-handles store const pointers to registries and offer a restricted set of
|
|
|
-functionalities.
|
|
|
+Non-const handles are also implicitly convertible to const handles out of the
|
|
|
+box but not the other way around.
|
|
|
|
|
|
This class is intended to simplify function signatures. In case of functions
|
|
|
that take a registry and an entity and do most of their work on that entity,
|
|
|
@@ -828,15 +799,15 @@ it. For example:
|
|
|
organizer.emplace<&free_function>("func");
|
|
|
```
|
|
|
|
|
|
-When a function of any type is registered with the organizer, everything it
|
|
|
-accesses is considered a _resource_ (views are _unpacked_ and their types are
|
|
|
-treated as resources). The _constness_ of the type also dictates its access mode
|
|
|
-(RO/RW). In turn, this affects the resulting graph, since it influences the
|
|
|
-possibility of launching tasks in parallel.<br/>
|
|
|
+When a function is registered with the organizer, everything it accesses is
|
|
|
+considered a _resource_ (views are _unpacked_ and their types are treated as
|
|
|
+resources). The _constness_ of a type also dictates its access mode (RO/RW). In
|
|
|
+turn, this affects the resulting graph, since it influences the possibility of
|
|
|
+launching tasks in parallel.<br/>
|
|
|
As for the registry, if a function doesn't explicitly request it or requires a
|
|
|
constant reference to it, it's considered a read-only access. Otherwise, it's
|
|
|
-considered as read-write access. All functions will still have the registry
|
|
|
-among their resources.
|
|
|
+considered as read-write access. All functions have the registry among their
|
|
|
+resources.
|
|
|
|
|
|
When registering a function, users can also require resources that aren't in the
|
|
|
list of parameters of the function itself. These are declared as template
|
|
|
@@ -854,8 +825,8 @@ organizer.emplace<&free_function, const renderable>("func");
|
|
|
```
|
|
|
|
|
|
In this case, even if `renderable` appears among the parameters of the function
|
|
|
-as not constant, it will be treated as constant as regards the generation of the
|
|
|
-task graph.
|
|
|
+as not constant, it's treated as constant as regards the generation of the task
|
|
|
+graph.
|
|
|
|
|
|
To generate the task graph, the organizer offers the `graph` member function:
|
|
|
|
|
|
@@ -863,22 +834,22 @@ To generate the task graph, the organizer offers the `graph` member function:
|
|
|
std::vector<entt::organizer::vertex> graph = organizer.graph();
|
|
|
```
|
|
|
|
|
|
-The graph is returned in the form of an adjacency list. Each vertex offers the
|
|
|
+A graph is returned in the form of an adjacency list. Each vertex offers the
|
|
|
following features:
|
|
|
|
|
|
-* `ro_count` and `rw_count`: they return the number of resources accessed in
|
|
|
- read-only or read-write mode.
|
|
|
+* `ro_count` and `rw_count`: the number of resources accessed in read-only or
|
|
|
+ read-write mode.
|
|
|
|
|
|
-* `ro_dependency` and `rw_dependency`: useful for retrieving the type info
|
|
|
- objects associated with the parameters of the underlying function.
|
|
|
+* `ro_dependency` and `rw_dependency`: type info objects associated with the
|
|
|
+ parameters of the underlying function.
|
|
|
|
|
|
-* `top_level`: indicates whether a node is a top level one, that is, it has no
|
|
|
- entering edges.
|
|
|
+* `top_level`: true if a node is a top level one (it has no entering edges),
|
|
|
+ false otherwise.
|
|
|
|
|
|
-* `info`: returns the type info object associated with the underlying function.
|
|
|
+* `info`: type info object associated with the underlying function.
|
|
|
|
|
|
-* `name`: returns the name associated with the given vertex if any, a null
|
|
|
- pointer otherwise.
|
|
|
+* `name`: the name associated with the given vertex if any, a null pointer
|
|
|
+ otherwise.
|
|
|
|
|
|
* `callback`: a pointer to the function to execute and whose function type is
|
|
|
`void(const void *, entt::registry &)`.
|
|
|
@@ -889,8 +860,8 @@ following features:
|
|
|
within the adjacency list.
|
|
|
|
|
|
Since the creation of pools and resources within the registry isn't necessarily
|
|
|
-thread safe, each vertex also offers a `prepare` function which can be called to
|
|
|
-setup a registry for execution with the created graph:
|
|
|
+thread safe, each vertex also offers a `prepare` function which is used to setup
|
|
|
+a registry for execution with the created graph:
|
|
|
|
|
|
```cpp
|
|
|
auto graph = organizer.graph();
|
|
|
@@ -908,8 +879,8 @@ use the preferred tool.
|
|
|
|
|
|
Each registry has a _context_ associated with it, which is an `any` object map
|
|
|
accessible by both type and _name_ for convenience. The _name_ isn't really a
|
|
|
-name though. In fact, it's a numeric id of type `id_type` to be used as a key
|
|
|
-for the variable. Any value is accepted, even runtime ones.<br/>
|
|
|
+name though. In fact, it's a numeric id of type `id_type` used as a key for the
|
|
|
+variable. Any value is accepted, even runtime ones.<br/>
|
|
|
The context is returned via the `ctx` functions and offers a minimal set of
|
|
|
feature including the following:
|
|
|
|
|
|
@@ -939,9 +910,9 @@ registry.ctx().erase<my_type>();
|
|
|
registry.ctx().erase<my_type>("my_variable"_hs);
|
|
|
```
|
|
|
|
|
|
-The type of a context variable must be such that it's default constructible and
|
|
|
-can be moved. If the supplied type doesn't match that of the variable when using
|
|
|
-a _name_, the operation will fail.<br/>
|
|
|
+Context variable must be both default constructible and movable. If the supplied
|
|
|
+type doesn't match that of the variable when using a _name_, the operation
|
|
|
+fails.<br/>
|
|
|
For all users who want to use the context but don't want to create elements, the
|
|
|
`contains` and `find` functions are also available:
|
|
|
|
|
|
@@ -955,9 +926,9 @@ the variable to look up, as does `at`.
|
|
|
|
|
|
### Aliased properties
|
|
|
|
|
|
-Context variables can also be used to create aliases for existing variables that
|
|
|
-aren't directly managed by the registry. In this case, it's also possible to
|
|
|
-make them read-only.<br/>
|
|
|
+A context also supports creating _aliases_ for existing variables that aren't
|
|
|
+directly managed by the registry. Const and therefore read-only variables are
|
|
|
+also accepted.<br/>
|
|
|
To do that, the type used upon construction must be a reference type and an
|
|
|
lvalue is necessarily provided as an argument:
|
|
|
|
|
|
@@ -987,8 +958,8 @@ const my_type *ptr = registry.ctx().find<const my_type>();
|
|
|
const my_type &var = registry.ctx().get<const my_type>();
|
|
|
```
|
|
|
|
|
|
-Aliased properties can be erased as it happens with any other variable.
|
|
|
-Similarly, they can also be associated with user-generated _names_ (or ids).
|
|
|
+Aliased properties are erased as it happens with any other variable. Similarly,
|
|
|
+it's also possible to assign them a _name_.
|
|
|
|
|
|
## Component traits
|
|
|
|
|
|
@@ -1066,7 +1037,7 @@ definition when needed.<br/>
|
|
|
Views and groups adapt accordingly when they detect a storage with a different
|
|
|
deletion policy than the default. In particular:
|
|
|
|
|
|
-* Groups are incompatible with stable storage and will even refuse to compile.
|
|
|
+* Groups are incompatible with stable storage and even refuse to compile.
|
|
|
* Multi type and runtime views are completely transparent to storage policies.
|
|
|
* Single type views for stable storage types offer the same interface of multi
|
|
|
type views. For example, only `size_hint` is available.
|
|
|
@@ -1111,8 +1082,8 @@ struct transform {
|
|
|
|
|
|
Furthermore, it's quite common for a group of elements to be created close in
|
|
|
time and therefore fallback into adjacent positions, thus favoring locality even
|
|
|
-on random accesses. Locality that won't be sacrificed over time given the
|
|
|
-stability of storage positions, with undoubted performance advantages.
|
|
|
+on random accesses. Locality that isn't sacrificed over time given the stability
|
|
|
+of storage positions, with undoubted performance advantages.
|
|
|
|
|
|
## Meet the runtime
|
|
|
|
|
|
@@ -1120,19 +1091,19 @@ stability of storage positions, with undoubted performance advantages.
|
|
|
this can have its downsides (well known to those familiar with type erasure
|
|
|
techniques).<br/>
|
|
|
To fill the gap, the library also provides a bunch of utilities and feature that
|
|
|
-can be very useful to handle types and pools at runtime.
|
|
|
+are very useful to handle types and pools at runtime.
|
|
|
|
|
|
### A base class to rule them all
|
|
|
|
|
|
-Storage classes are fully self-contained types. These can be extended via mixins
|
|
|
+Storage classes are fully self-contained types. They are _extended_ via mixins
|
|
|
to add more functionalities (generic or type specific). In addition, they offer
|
|
|
a basic set of functions that already allow users to go very far.<br/>
|
|
|
The aim is to limit the need for customizations as much as possible, offering
|
|
|
what is usually necessary for the vast majority of cases.
|
|
|
|
|
|
-When a storage is used through its base class (i.e. when its actual type isn't
|
|
|
-known), there is always the possibility of receiving a `type_info` describing
|
|
|
-the type of the objects associated with the entities (if any):
|
|
|
+When a storage is used through its base class (for example, when its actual type
|
|
|
+isn't known), there is always the possibility of receiving a `type_info` object
|
|
|
+for the type of elements associated with the entities (if any):
|
|
|
|
|
|
```cpp
|
|
|
if(entt::type_id<velocity>() == base.type()) {
|
|
|
@@ -1191,14 +1162,8 @@ depending on the type.
|
|
|
|
|
|
### Beam me up, registry
|
|
|
|
|
|
-`EnTT` is strongly based on types and has always allowed to create only one
|
|
|
-storage of a certain type within a registry.<br/>
|
|
|
-However, this doesn't work well for users who want to create multiple storage of
|
|
|
-the same type associated with different _names_, such as for interacting with a
|
|
|
-scripting system.
|
|
|
-
|
|
|
-Nowadays, the library has solved this problem and offers the possibility of
|
|
|
-associating a type with a _name_ (or rather, a numeric identifier):
|
|
|
+`EnTT` allows the user to assign a _name_ (or rather, a numeric identifier) to a
|
|
|
+type and then create multiple pools of the same type:
|
|
|
|
|
|
```cpp
|
|
|
using namespace entt::literals;
|
|
|
@@ -1207,10 +1172,8 @@ auto &&storage = registry.storage<velocity>("second pool"_hs);
|
|
|
|
|
|
If a name isn't provided, the default storage associated with the given type is
|
|
|
always returned.<br/>
|
|
|
-Since the storage are also self-contained, the registry doesn't try in any way
|
|
|
-to _duplicate_ its API and offer parallel functionalities for storage discovered
|
|
|
-by name.<br/>
|
|
|
-However, there is still no limit to the possibilities of use. For example:
|
|
|
+Since the storage are also self-contained, the registry doesn't _duplicate_ its
|
|
|
+own API for them. However, there is still no limit to the possibilities of use:
|
|
|
|
|
|
```cpp
|
|
|
auto &&other = registry.storage<velocity>("other"_hs);
|
|
|
@@ -1219,13 +1182,13 @@ registry.emplace<velocity>(entity);
|
|
|
storage.emplace(entity);
|
|
|
```
|
|
|
|
|
|
-In other words, anything that can be done via the registry interface can also be
|
|
|
-done directly on the reference storage.<br/>
|
|
|
+Anything that can be done via the registry interface can also be done directly
|
|
|
+on the reference storage.<br/>
|
|
|
On the other hand, those calls involving all storage are guaranteed to also
|
|
|
_reach_ manually created ones:
|
|
|
|
|
|
```cpp
|
|
|
-// will remove the entity from both storage
|
|
|
+// removes the entity from both storage
|
|
|
registry.destroy(entity);
|
|
|
```
|
|
|
|
|
|
@@ -1245,13 +1208,11 @@ auto join = registry.view<velocity>() | entt::basic_view{registry.storage<veloci
|
|
|
|
|
|
The possibility of direct use of storage combined with the freedom of being able
|
|
|
to create and use more than one of the same type opens the door to the use of
|
|
|
-`EnTT` _at runtime_, which was previously quite limited.<br/>
|
|
|
-Sure the basic design remains very type-bound, but finally it's no longer bound
|
|
|
-to this one option alone.
|
|
|
+`EnTT` _at runtime_, which was previously quite limited.
|
|
|
|
|
|
## Snapshot: complete vs continuous
|
|
|
|
|
|
-The `registry` class offers basic support to serialization.<br/>
|
|
|
+This module comes with bare minimum support to serialization.<br/>
|
|
|
It doesn't convert components to bytes directly, there wasn't the need of
|
|
|
another tool for serialization out there. Instead, it accepts an opaque object
|
|
|
with a suitable interface (namely an _archive_) to serialize its internal data
|
|
|
@@ -1277,32 +1238,17 @@ entt::snapshot{registry}
|
|
|
```
|
|
|
|
|
|
It isn't necessary to invoke all functions each and every time. What functions
|
|
|
-to use in which case mostly depends on the goal and there is not a golden rule
|
|
|
-for that.
|
|
|
+to use in which case mostly depends on the goal.
|
|
|
|
|
|
The `entities` member function makes the snapshot serialize all entities (both
|
|
|
those still alive and those released) along with their versions.<br/>
|
|
|
-On the other hand, the `component` member function is a function template the
|
|
|
-aim of which is to store aside components. The presence of a template parameter
|
|
|
-list is a consequence of a couple of design choices from the past and in the
|
|
|
-present:
|
|
|
-
|
|
|
-* First of all, there is no reason to force a user to serialize all the
|
|
|
- components at once and most of the time it isn't desiderable. As an example,
|
|
|
- in case the stuff for the HUD in a game is put into the registry for some
|
|
|
- reasons, its components can be freely discarded during a serialization step
|
|
|
- because probably the software already knows how to reconstruct them correctly.
|
|
|
-
|
|
|
-* Furthermore, the registry makes heavy use of _type-erasure_ techniques
|
|
|
- internally and doesn't know at any time what component types it contains.
|
|
|
- Therefore being explicit at the call site is mandatory.
|
|
|
-
|
|
|
+On the other hand, the `component` member function template is meant to store
|
|
|
+aside components.<br/>
|
|
|
There exists also another version of the `component` member function that
|
|
|
accepts a range of entities to serialize. This version is a bit slower than the
|
|
|
other one, mainly because it iterates the range of entities more than once for
|
|
|
internal purposes. However, it can be used to filter out those entities that
|
|
|
-shouldn't be serialized for some reasons.<br/>
|
|
|
-As an example:
|
|
|
+shouldn't be serialized for some reasons:
|
|
|
|
|
|
```cpp
|
|
|
const auto view = registry.view<serialize>();
|
|
|
@@ -1320,10 +1266,9 @@ The following sections describe both loaders and archives in details.
|
|
|
|
|
|
### Snapshot loader
|
|
|
|
|
|
-A snapshot loader requires that the destination registry be empty and loads all
|
|
|
+A snapshot loader requires that the destination registry be empty. It loads all
|
|
|
the data at once while keeping intact the identifiers that the entities
|
|
|
-originally had.<br/>
|
|
|
-To use it, just pass to the constructor a valid registry:
|
|
|
+originally had:
|
|
|
|
|
|
```cpp
|
|
|
input_archive input;
|
|
|
@@ -1335,28 +1280,22 @@ entt::snapshot_loader{registry}
|
|
|
```
|
|
|
|
|
|
It isn't necessary to invoke all functions each and every time. What functions
|
|
|
-to use in which case mostly depends on the goal and there is not a golden rule
|
|
|
-for that. For obvious reasons, what is important is that the data are restored
|
|
|
-in exactly the same order in which they were serialized.
|
|
|
+to use in which case mostly depends on the goal.<br/>
|
|
|
+For obvious reasons, what is important is that the data are restored in exactly
|
|
|
+the same order in which they were serialized.
|
|
|
|
|
|
The `entities` member function restores the sets of entities and the versions
|
|
|
-that they originally had at the source.
|
|
|
-
|
|
|
+that they originally had at the source.<br/>
|
|
|
The `component` member function restores all and only the components specified
|
|
|
-and assigns them to the right entities. Note that the template parameter list
|
|
|
-must be exactly the same used during the serialization.
|
|
|
-
|
|
|
-The `orphans` member function literally releases those entities that have no
|
|
|
-components attached. It's usually useless if the snapshot is a full dump of the
|
|
|
-source. However, in case all the entities are serialized but only few components
|
|
|
-are saved, it could happen that some of the entities have no components once
|
|
|
-restored. The best the users can do to deal with them is to release those
|
|
|
-entities and thus update their versions.
|
|
|
+and assigns them to the right entities. The template parameter list must be the
|
|
|
+same used during the serialization.<br/>
|
|
|
+The `orphans` member function releases the entities that have no components, if
|
|
|
+any.
|
|
|
|
|
|
### Continuous loader
|
|
|
|
|
|
A continuous loader is designed to load data from a source registry to a
|
|
|
-(possibly) non-empty destination. The loader can accommodate in a registry more
|
|
|
+(possibly) non-empty destination. The loader accommodates in a registry more
|
|
|
than one snapshot in a sort of _continuous loading_ that updates the destination
|
|
|
one step at a time.<br/>
|
|
|
Identifiers that entities originally had are not transferred to the target.
|
|
|
@@ -1366,9 +1305,7 @@ automatically identifiers that are part of components (as an example, as data
|
|
|
members or gathered in a container).<br/>
|
|
|
Another difference with the snapshot loader is that the continuous loader has an
|
|
|
internal state that must persist over time. Therefore, there is no reason to
|
|
|
-limit its lifetime to that of a temporary object.
|
|
|
-
|
|
|
-Example of use:
|
|
|
+limit its lifetime to that of a temporary object:
|
|
|
|
|
|
```cpp
|
|
|
entt::continuous_loader loader{registry};
|
|
|
@@ -1381,26 +1318,21 @@ loader.entities(input)
|
|
|
```
|
|
|
|
|
|
It isn't necessary to invoke all functions each and every time. What functions
|
|
|
-to use in which case mostly depends on the goal and there is not a golden rule
|
|
|
-for that. For obvious reasons, what is important is that the data are restored
|
|
|
-in exactly the same order in which they were serialized.
|
|
|
+to use in which case mostly depends on the goal.<br/>
|
|
|
+For obvious reasons, what is important is that the data are restored in exactly
|
|
|
+the same order in which they were serialized.
|
|
|
|
|
|
The `entities` member function restores groups of entities and maps each entity
|
|
|
-to a local counterpart when required. In other terms, for each remote entity
|
|
|
-identifier not yet registered by the loader, it creates a local identifier so
|
|
|
-that it can keep the local entity in sync with the remote one.
|
|
|
-
|
|
|
+to a local counterpart when required. For each remote entity identifier not yet
|
|
|
+registered by the loader, a local identifier is created so as to keep the local
|
|
|
+entity in sync with the remote one.<br/>
|
|
|
The `component` member function restores all and only the components specified
|
|
|
-and assigns them to the right entities.<br/>
|
|
|
-In case the component contains entities itself (either as data members of type
|
|
|
-`entt::entity` or as containers of entities), the loader can update them
|
|
|
-automatically. To do that, it's enough to specify the data members to update as
|
|
|
-shown in the example.
|
|
|
-
|
|
|
-The `orphans` member function literally releases those entities that have no
|
|
|
-components after a restore. It has exactly the same purpose described in the
|
|
|
-previous section and works the same way.
|
|
|
-
|
|
|
+and assigns them to the right entities. In case the component contains entities
|
|
|
+itself (either as data members of type `entt::entity` or in a container), the
|
|
|
+loader can update them automatically. To do that, it's enough to specify the
|
|
|
+data members to update as shown in the example.<br/>
|
|
|
+The `orphans` member function releases the entities that have no components
|
|
|
+after a restore.<br/>
|
|
|
Finally, `shrink` helps to purge local entities that no longer have a remote
|
|
|
conterpart. Users should invoke this member function after restoring each
|
|
|
snapshot, unless they know exactly what they are doing.
|
|
|
@@ -1413,15 +1345,15 @@ are invoked by the snapshot class and the loaders.
|
|
|
|
|
|
In particular:
|
|
|
|
|
|
-* An output archive, the one used when creating a snapshot, must expose a
|
|
|
- function call operator with the following signature to store entities:
|
|
|
+* An output archive (the one used when creating a snapshot) exposes a function
|
|
|
+ call operator with the following signature to store entities:
|
|
|
|
|
|
```cpp
|
|
|
void operator()(entt::entity);
|
|
|
```
|
|
|
|
|
|
Where `entt::entity` is the type of the entities used by the registry.<br/>
|
|
|
- Note that all member functions of the snapshot class make also an initial call
|
|
|
+ Note that all member functions of the snapshot class also make an initial call
|
|
|
to store aside the _size_ of the set they are going to store. In this case,
|
|
|
the expected function type for the function call operator is:
|
|
|
|
|
|
@@ -1429,45 +1361,45 @@ In particular:
|
|
|
void operator()(std::underlying_type_t<entt::entity>);
|
|
|
```
|
|
|
|
|
|
- In addition, an archive must accept a pair of entity and component for each
|
|
|
- type to be serialized. Therefore, given a type `T`, the archive must contain a
|
|
|
- function call operator with the following signature:
|
|
|
+ In addition, an archive accepts a pair of entity and component for each type
|
|
|
+ to serialize. Therefore, given a type `T`, the archive offers a function call
|
|
|
+ operator with the following signature:
|
|
|
|
|
|
```cpp
|
|
|
void operator()(entt::entity, const T &);
|
|
|
```
|
|
|
|
|
|
The output archive can freely decide how to serialize the data. The registry
|
|
|
- is not affected at all by the decision.
|
|
|
+ isn't affected at all by the decision.
|
|
|
|
|
|
-* An input archive, the one used when restoring a snapshot, must expose a
|
|
|
- function call operator with the following signature to load entities:
|
|
|
+* An input archive (the one used when restoring a snapshot) exposes a function
|
|
|
+ call operator with the following signature to load entities:
|
|
|
|
|
|
```cpp
|
|
|
void operator()(entt::entity &);
|
|
|
```
|
|
|
|
|
|
Where `entt::entity` is the type of the entities used by the registry. Each
|
|
|
- time the function is invoked, the archive must read the next element from the
|
|
|
- underlying storage and copy it in the given variable.<br/>
|
|
|
- Note that all member functions of a loader class make also an initial call to
|
|
|
- read the _size_ of the set they are going to load. In this case, the expected
|
|
|
- function type for the function call operator is:
|
|
|
+ time the function is invoked, the archive reads the next element from the
|
|
|
+ underlying storage and copies it in the given variable.<br/>
|
|
|
+ All member functions of a loader class also make an initial call to read the
|
|
|
+ _size_ of the set they are going to load. In this case, the expected function
|
|
|
+ type for the function call operator is:
|
|
|
|
|
|
```cpp
|
|
|
void operator()(std::underlying_type_t<entt::entity> &);
|
|
|
```
|
|
|
|
|
|
- In addition, the archive must accept a pair of references to an entity and its
|
|
|
- component for each type to be restored. Therefore, given a type `T`, the
|
|
|
- archive must contain a function call operator with the following signature:
|
|
|
+ In addition, the archive accepts a pair of references to an entity and its
|
|
|
+ component for each type to restore. Therefore, given a type `T`, the archive
|
|
|
+ contains a function call operator with the following signature:
|
|
|
|
|
|
```cpp
|
|
|
void operator()(entt::entity &, T &);
|
|
|
```
|
|
|
|
|
|
- Every time such an operator is invoked, the archive must read the next
|
|
|
- elements from the underlying storage and copy them in the given variables.
|
|
|
+ Every time this operator is invoked, the archive reads the next elements from
|
|
|
+ the underlying storage and copies them in the given variables.
|
|
|
|
|
|
### One example to rule them all
|
|
|
|
|
|
@@ -1476,9 +1408,8 @@ a well known library for serialization as an archive. It uses
|
|
|
[`Cereal C++`](https://uscilab.github.io/cereal/) under the hood, mainly
|
|
|
because I wanted to learn how it works at the time I was writing the code.
|
|
|
|
|
|
-The code is not production-ready and it isn't neither the only nor (probably)
|
|
|
-the best way to do it. However, feel free to use it at your own risk.
|
|
|
-
|
|
|
+The code **isn't** production-ready and it isn't neither the only nor (probably)
|
|
|
+the best way to do it. However, feel free to use it at your own risk.<br/>
|
|
|
The basic idea is to store everything in a group of queues in memory, then bring
|
|
|
everything back to the registry with different loaders.
|
|
|
|