EnTT  3.10.0
snapshot.hpp
1 #ifndef ENTT_ENTITY_SNAPSHOT_HPP
2 #define ENTT_ENTITY_SNAPSHOT_HPP
3 
4 #include <array>
5 #include <cstddef>
6 #include <iterator>
7 #include <tuple>
8 #include <type_traits>
9 #include <utility>
10 #include <vector>
11 #include "../config/config.h"
12 #include "../container/dense_map.hpp"
13 #include "../core/type_traits.hpp"
14 #include "component.hpp"
15 #include "entity.hpp"
16 #include "fwd.hpp"
17 #include "registry.hpp"
18 
19 namespace entt {
20 
31 template<typename Entity>
34 
35  template<typename Component, typename Archive, typename It>
36  void get(Archive &archive, std::size_t sz, It first, It last) const {
37  const auto view = reg->template view<std::add_const_t<Component>>();
38  archive(typename entity_traits::entity_type(sz));
39 
40  while(first != last) {
41  const auto entt = *(first++);
42 
43  if(reg->template all_of<Component>(entt)) {
44  std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt)));
45  }
46  }
47  }
48 
49  template<typename... Component, typename Archive, typename It, std::size_t... Index>
50  void component(Archive &archive, It first, It last, std::index_sequence<Index...>) const {
51  std::array<std::size_t, sizeof...(Index)> size{};
52  auto begin = first;
53 
54  while(begin != last) {
55  const auto entt = *(begin++);
56  ((reg->template all_of<Component>(entt) ? ++size[Index] : 0u), ...);
57  }
58 
59  (get<Component>(archive, size[Index], first, last), ...);
60  }
61 
62 public:
64  using entity_type = Entity;
65 
70  basic_snapshot(const basic_registry<entity_type> &source) ENTT_NOEXCEPT
71  : reg{&source} {}
72 
74  basic_snapshot(basic_snapshot &&) ENTT_NOEXCEPT = default;
75 
77  basic_snapshot &operator=(basic_snapshot &&) ENTT_NOEXCEPT = default;
78 
89  template<typename Archive>
90  const basic_snapshot &entities(Archive &archive) const {
91  const auto sz = reg->size();
92 
93  archive(typename entity_traits::entity_type(sz + 1u));
94  archive(reg->released());
95 
96  for(auto first = reg->data(), last = first + sz; first != last; ++first) {
97  archive(*first);
98  }
99 
100  return *this;
101  }
102 
114  template<typename... Component, typename Archive>
115  const basic_snapshot &component(Archive &archive) const {
116  if constexpr(sizeof...(Component) == 1u) {
117  const auto view = reg->template view<const Component...>();
118  (component<Component>(archive, view.rbegin(), view.rend()), ...);
119  return *this;
120  } else {
121  (component<Component>(archive), ...);
122  return *this;
123  }
124  }
125 
140  template<typename... Component, typename Archive, typename It>
141  const basic_snapshot &component(Archive &archive, It first, It last) const {
142  component<Component...>(archive, first, last, std::index_sequence_for<Component...>{});
143  return *this;
144  }
145 
146 private:
147  const basic_registry<entity_type> *reg;
148 };
149 
160 template<typename Entity>
163 
164  template<typename Type, typename Archive>
165  void assign(Archive &archive) const {
166  typename entity_traits::entity_type length{};
168 
169  archive(length);
170 
171  if constexpr(ignore_as_empty_v<Type>) {
172  while(length--) {
173  archive(entt);
174  const auto entity = reg->valid(entt) ? entt : reg->create(entt);
175  ENTT_ASSERT(entity == entt, "Entity not available for use");
176  reg->template emplace<Type>(entt);
177  }
178  } else {
179  Type instance;
180 
181  while(length--) {
182  archive(entt, instance);
183  const auto entity = reg->valid(entt) ? entt : reg->create(entt);
184  ENTT_ASSERT(entity == entt, "Entity not available for use");
185  reg->template emplace<Type>(entt, std::move(instance));
186  }
187  }
188  }
189 
190 public:
192  using entity_type = Entity;
193 
199  : reg{&source} {
200  // restoring a snapshot as a whole requires a clean registry
201  ENTT_ASSERT(reg->empty(), "Registry must be empty");
202  }
203 
205  basic_snapshot_loader(basic_snapshot_loader &&) ENTT_NOEXCEPT = default;
206 
208  basic_snapshot_loader &operator=(basic_snapshot_loader &&) ENTT_NOEXCEPT = default;
209 
220  template<typename Archive>
221  const basic_snapshot_loader &entities(Archive &archive) const {
222  typename entity_traits::entity_type length{};
223 
224  archive(length);
225  std::vector<entity_type> all(length);
226 
227  for(std::size_t pos{}; pos < length; ++pos) {
228  archive(all[pos]);
229  }
230 
231  reg->assign(++all.cbegin(), all.cend(), all[0u]);
232 
233  return *this;
234  }
235 
249  template<typename... Component, typename Archive>
250  const basic_snapshot_loader &component(Archive &archive) const {
251  (assign<Component>(archive), ...);
252  return *this;
253  }
254 
266  reg->each([this](const auto entt) {
267  if(reg->orphan(entt)) {
268  reg->release(entt);
269  }
270  });
271 
272  return *this;
273  }
274 
275 private:
277 };
278 
295 template<typename Entity>
298 
299  void destroy(Entity entt) {
300  if(const auto it = remloc.find(entt); it == remloc.cend()) {
301  const auto local = reg->create();
302  remloc.emplace(entt, std::make_pair(local, true));
303  reg->destroy(local);
304  }
305  }
306 
307  void restore(Entity entt) {
308  const auto it = remloc.find(entt);
309 
310  if(it == remloc.cend()) {
311  const auto local = reg->create();
312  remloc.emplace(entt, std::make_pair(local, true));
313  } else {
314  if(!reg->valid(remloc[entt].first)) {
315  remloc[entt].first = reg->create();
316  }
317 
318  // set the dirty flag
319  remloc[entt].second = true;
320  }
321  }
322 
323  template<typename Container>
324  auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
325  // map like container
326  Container other;
327 
328  for(auto &&pair: container) {
329  using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
330  using second_type = typename std::decay_t<decltype(pair)>::second_type;
331 
332  if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
333  other.emplace(map(pair.first), map(pair.second));
334  } else if constexpr(std::is_same_v<first_type, entity_type>) {
335  other.emplace(map(pair.first), std::move(pair.second));
336  } else {
337  static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
338  other.emplace(std::move(pair.first), map(pair.second));
339  }
340  }
341 
342  using std::swap;
343  swap(container, other);
344  }
345 
346  template<typename Container>
347  auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
348  // vector like container
349  static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
350 
351  for(auto &&entt: container) {
352  entt = map(entt);
353  }
354  }
355 
356  template<typename Other, typename Type, typename Member>
357  void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type::*member) {
358  if constexpr(!std::is_same_v<Other, Type>) {
359  return;
360  } else if constexpr(std::is_same_v<Member, entity_type>) {
361  instance.*member = map(instance.*member);
362  } else {
363  // maybe a container? let's try...
364  update(0, instance.*member);
365  }
366  }
367 
368  template<typename Component>
369  void remove_if_exists() {
370  for(auto &&ref: remloc) {
371  const auto local = ref.second.first;
372 
373  if(reg->valid(local)) {
374  reg->template remove<Component>(local);
375  }
376  }
377  }
378 
379  template<typename Other, typename Archive, typename... Type, typename... Member>
380  void assign(Archive &archive, [[maybe_unused]] Member Type::*...member) {
381  typename entity_traits::entity_type length{};
383 
384  archive(length);
385 
386  if constexpr(ignore_as_empty_v<Other>) {
387  while(length--) {
388  archive(entt);
389  restore(entt);
390  reg->template emplace_or_replace<Other>(map(entt));
391  }
392  } else {
393  Other instance;
394 
395  while(length--) {
396  archive(entt, instance);
397  (update(instance, member), ...);
398  restore(entt);
399  reg->template emplace_or_replace<Other>(map(entt), std::move(instance));
400  }
401  }
402  }
403 
404 public:
406  using entity_type = Entity;
407 
413  : reg{&source} {}
414 
417 
420 
431  template<typename Archive>
432  basic_continuous_loader &entities(Archive &archive) {
433  typename entity_traits::entity_type length{};
434  entity_type entt{};
435 
436  archive(length);
437  // discards the head of the list of destroyed entities
438  archive(entt);
439 
440  for(std::size_t pos{}, last = length - 1u; pos < last; ++pos) {
441  archive(entt);
442 
443  if(const auto entity = entity_traits::to_entity(entt); entity == pos) {
444  restore(entt);
445  } else {
446  destroy(entt);
447  }
448  }
449 
450  return *this;
451  }
452 
472  template<typename... Component, typename Archive, typename... Type, typename... Member>
473  basic_continuous_loader &component(Archive &archive, Member Type::*...member) {
474  (remove_if_exists<Component>(), ...);
475  (assign<Component>(archive, member...), ...);
476  return *this;
477  }
478 
488  auto it = remloc.begin();
489 
490  while(it != remloc.cend()) {
491  const auto local = it->second.first;
492  bool &dirty = it->second.second;
493 
494  if(dirty) {
495  dirty = false;
496  ++it;
497  } else {
498  if(reg->valid(local)) {
499  reg->destroy(local);
500  }
501 
502  it = remloc.erase(it);
503  }
504  }
505 
506  return *this;
507  }
508 
520  reg->each([this](const auto entt) {
521  if(reg->orphan(entt)) {
522  reg->release(entt);
523  }
524  });
525 
526  return *this;
527  }
528 
534  [[nodiscard]] bool contains(entity_type entt) const ENTT_NOEXCEPT {
535  return (remloc.find(entt) != remloc.cend());
536  }
537 
543  [[nodiscard]] entity_type map(entity_type entt) const ENTT_NOEXCEPT {
544  const auto it = remloc.find(entt);
545  entity_type other = null;
546 
547  if(it != remloc.cend()) {
548  other = it->second.first;
549  }
550 
551  return other;
552  }
553 
554 private:
557 };
558 
559 } // namespace entt
560 
561 #endif
Utility class for continuous loading.
Definition: snapshot.hpp:296
basic_continuous_loader & shrink()
Helps to purge entities that no longer have a conterpart.
Definition: snapshot.hpp:487
basic_continuous_loader & component(Archive &archive, Member Type::*...member)
Restores components and assigns them to the right entities.
Definition: snapshot.hpp:473
bool contains(entity_type entt) const
Tests if a loader knows about a given entity.
Definition: snapshot.hpp:534
basic_continuous_loader(basic_continuous_loader &&)=default
Default move constructor.
entity_type map(entity_type entt) const
Returns the identifier to which an entity refers.
Definition: snapshot.hpp:543
Entity entity_type
Underlying entity identifier.
Definition: snapshot.hpp:406
basic_continuous_loader & orphans()
Destroys those entities that have no components.
Definition: snapshot.hpp:519
basic_continuous_loader & entities(Archive &archive)
Restores entities that were in use during serialization.
Definition: snapshot.hpp:432
basic_continuous_loader(basic_registry< entity_type > &source)
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:412
basic_continuous_loader & operator=(basic_continuous_loader &&)=default
Default move assignment operator.
bool orphan(const entity_type entity) const
Checks if an entity has components assigned.
Definition: registry.hpp:1141
bool valid(const entity_type entity) const
Checks if an identifier refers to a valid entity.
Definition: registry.hpp:538
void assign(It first, It last, const entity_type destroyed)
Assigns identifiers to an empty registry.
Definition: registry.hpp:635
entity_type released() const
Returns the head of the list of released entities.
Definition: registry.hpp:529
bool empty() const
Checks whether the registry is empty (no entities still in use).
Definition: registry.hpp:501
size_type size() const
Returns the number of entities created so far.
Definition: registry.hpp:462
version_type destroy(const entity_type entity)
Destroys an entity and releases its identifier.
Definition: registry.hpp:702
void each(Func func) const
Iterates all the entities that are still in use.
Definition: registry.hpp:1122
entity_type create()
Creates a new entity or recycles a destroyed one.
Definition: registry.hpp:558
const entity_type * data() const
Direct access to the list of entities of a registry.
Definition: registry.hpp:517
Utility class to restore a snapshot as a whole.
Definition: snapshot.hpp:161
const basic_snapshot_loader & entities(Archive &archive) const
Restores entities that were in use during serialization.
Definition: snapshot.hpp:221
Entity entity_type
Underlying entity identifier.
Definition: snapshot.hpp:192
basic_snapshot_loader(basic_registry< entity_type > &source)
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:198
basic_snapshot_loader(basic_snapshot_loader &&)=default
Default move constructor.
const basic_snapshot_loader & orphans() const
Destroys those entities that have no components.
Definition: snapshot.hpp:265
const basic_snapshot_loader & component(Archive &archive) const
Restores components and assigns them to the right entities.
Definition: snapshot.hpp:250
Utility class to create snapshots from a registry.
Definition: snapshot.hpp:32
const basic_snapshot & component(Archive &archive, It first, It last) const
Puts aside the given components for the entities in a range.
Definition: snapshot.hpp:141
basic_snapshot(basic_snapshot &&)=default
Default move constructor.
const basic_snapshot & component(Archive &archive) const
Puts aside the given components.
Definition: snapshot.hpp:115
const basic_snapshot & entities(Archive &archive) const
Puts aside all the entities from the underlying registry.
Definition: snapshot.hpp:90
basic_snapshot(const basic_registry< entity_type > &source)
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:70
Entity entity_type
Underlying entity identifier.
Definition: snapshot.hpp:64
View implementation.
Definition: fwd.hpp:20
Associative container for key-value pairs with unique keys.
Definition: dense_map.hpp:265
const_iterator cend() const
Returns an iterator to the end.
Definition: dense_map.hpp:497
const_iterator begin() const
Returns an iterator to the beginning.
Definition: dense_map.hpp:478
iterator find(const key_type &key)
Finds an element with a given key.
Definition: dense_map.hpp:750
iterator erase(const_iterator pos)
Removes an element from a given position.
Definition: dense_map.hpp:657
std::pair< iterator, bool > emplace([[maybe_unused]] Args &&...args)
Constructs an element in-place, if the key does not exist.
Definition: dense_map.hpp:607
Entity traits.
Definition: entity.hpp:62
typename base_type::entity_type entity_type
Underlying entity type.
Definition: entity.hpp:69
static constexpr entity_type to_entity(const value_type value)
Returns the entity part once converted to the underlying type.
Definition: entity.hpp:91
EnTT default namespace.
Definition: dense_map.hpp:22
entity
Default entity identifier.
Definition: fwd.hpp:47
void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs)
Swaps two compressed pair objects.