EnTT  3.6.0
snapshot.hpp
1 #ifndef ENTT_ENTITY_SNAPSHOT_HPP
2 #define ENTT_ENTITY_SNAPSHOT_HPP
3 
4 
5 #include <array>
6 #include <cstddef>
7 #include <iterator>
8 #include <tuple>
9 #include <type_traits>
10 #include <unordered_map>
11 #include <utility>
12 #include <vector>
13 #include "../config/config.h"
14 #include "../core/type_traits.hpp"
15 #include "entity.hpp"
16 #include "fwd.hpp"
17 #include "registry.hpp"
18 
19 
20 namespace entt {
21 
22 
33 template<typename Entity>
36 
37  template<typename Component, typename Archive, typename It>
38  void get(Archive &archive, std::size_t sz, It first, It last) const {
39  const auto view = reg->template view<std::add_const_t<Component>>();
40  archive(typename traits_type::entity_type(sz));
41 
42  while(first != last) {
43  const auto entt = *(first++);
44 
45  if(reg->template has<Component>(entt)) {
46  std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt)));
47  }
48  }
49  }
50 
51  template<typename... Component, typename Archive, typename It, std::size_t... Index>
52  void component(Archive &archive, It first, It last, std::index_sequence<Index...>) const {
53  std::array<std::size_t, sizeof...(Index)> size{};
54  auto begin = first;
55 
56  while(begin != last) {
57  const auto entt = *(begin++);
58  ((reg->template has<Component>(entt) ? ++size[Index] : size[Index]), ...);
59  }
60 
61  (get<Component>(archive, size[Index], first, last), ...);
62  }
63 
64 public:
66  using entity_type = Entity;
67 
72  basic_snapshot(const basic_registry<entity_type> &source) ENTT_NOEXCEPT
73  : reg{&source}
74  {}
75 
78 
81 
92  template<typename Archive>
93  const basic_snapshot & entities(Archive &archive) const {
94  const auto sz = reg->size();
95 
96  archive(typename traits_type::entity_type(sz));
97 
98  for(auto first = reg->data(), last = first + sz; first != last; ++first) {
99  archive(*first);
100  }
101 
102  archive(reg->destroyed());
103 
104  return *this;
105  }
106 
118  template<typename... Component, typename Archive>
119  const basic_snapshot & component(Archive &archive) const {
120  (component<Component>(archive, reg->template data<Component>(), reg->template data<Component>() + reg->template size<Component>()), ...);
121  return *this;
122  }
123 
138  template<typename... Component, typename Archive, typename It>
139  const basic_snapshot & component(Archive &archive, It first, It last) const {
140  component<Component...>(archive, first, last, std::index_sequence_for<Component...>{});
141  return *this;
142  }
143 
144 private:
145  const basic_registry<entity_type> *reg;
146 };
147 
148 
159 template<typename Entity>
162 
163  template<typename Type, typename Archive>
164  void assign(Archive &archive) const {
165  typename traits_type::entity_type length{};
166  archive(length);
167 
168  entity_type entt{};
169 
170  if constexpr(std::tuple_size_v<decltype(reg->template view<Type>().get({}))> == 0) {
171  while(length--) {
172  archive(entt);
173  const auto entity = reg->valid(entt) ? entt : reg->create(entt);
174  ENTT_ASSERT(entity == entt);
175  reg->template emplace<Type>(entity);
176  }
177  } else {
178  Type instance{};
179 
180  while(length--) {
181  archive(entt, instance);
182  const auto entity = reg->valid(entt) ? entt : reg->create(entt);
183  ENTT_ASSERT(entity == entt);
184  reg->template emplace<Type>(entity, std::move(instance));
185  }
186  }
187  }
188 
189 public:
191  using entity_type = Entity;
192 
198  : reg{&source}
199  {
200  // restoring a snapshot as a whole requires a clean registry
201  ENTT_ASSERT(reg->empty());
202  }
203 
206 
209 
220  template<typename Archive>
221  const basic_snapshot_loader & entities(Archive &archive) const {
222  typename traits_type::entity_type length{};
223 
224  archive(length);
225  std::vector<entity_type> all(length);
226 
227  for(decltype(length) pos{}; pos < length; ++pos) {
228  archive(all[pos]);
229  }
230 
231  entity_type destroyed;
232  archive(destroyed);
233 
234  reg->assign(all.cbegin(), all.cend(), destroyed);
235 
236  return *this;
237  }
238 
252  template<typename... Component, typename Archive>
253  const basic_snapshot_loader & component(Archive &archive) const {
254  (assign<Component>(archive), ...);
255  return *this;
256  }
257 
268  const basic_snapshot_loader & orphans() const {
269  reg->orphans([this](const auto entt) {
270  reg->destroy(entt);
271  });
272 
273  return *this;
274  }
275 
276 private:
278 };
279 
280 
297 template<typename Entity>
300 
301  void destroy(Entity entt) {
302  if(const auto it = remloc.find(entt); it == remloc.cend()) {
303  const auto local = reg->create();
304  remloc.emplace(entt, std::make_pair(local, true));
305  reg->destroy(local);
306  }
307  }
308 
309  void restore(Entity entt) {
310  const auto it = remloc.find(entt);
311 
312  if(it == remloc.cend()) {
313  const auto local = reg->create();
314  remloc.emplace(entt, std::make_pair(local, true));
315  } else {
316  if(!reg->valid(remloc[entt].first)) {
317  remloc[entt].first = reg->create();
318  }
319 
320  // set the dirty flag
321  remloc[entt].second = true;
322  }
323  }
324 
325  template<typename Container>
326  auto update(int, Container &container)
327  -> decltype(typename Container::mapped_type{}, void()) {
328  // map like container
329  Container other;
330 
331  for(auto &&pair: container) {
332  using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
333  using second_type = typename std::decay_t<decltype(pair)>::second_type;
334 
335  if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
336  other.emplace(map(pair.first), map(pair.second));
337  } else if constexpr(std::is_same_v<first_type, entity_type>) {
338  other.emplace(map(pair.first), std::move(pair.second));
339  } else {
340  static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
341  other.emplace(std::move(pair.first), map(pair.second));
342  }
343  }
344 
345  std::swap(container, other);
346  }
347 
348  template<typename Container>
349  auto update(char, Container &container)
350  -> decltype(typename Container::value_type{}, void()) {
351  // vector like container
352  static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
353 
354  for(auto &&entt: container) {
355  entt = map(entt);
356  }
357  }
358 
359  template<typename Other, typename Type, typename Member>
360  void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type:: *member) {
361  if constexpr(!std::is_same_v<Other, Type>) {
362  return;
363  } else if constexpr(std::is_same_v<Member, entity_type>) {
364  instance.*member = map(instance.*member);
365  } else {
366  // maybe a container? let's try...
367  update(0, instance.*member);
368  }
369  }
370 
371  template<typename Component>
372  void remove_if_exists() {
373  for(auto &&ref: remloc) {
374  const auto local = ref.second.first;
375 
376  if(reg->valid(local)) {
377  reg->template remove_if_exists<Component>(local);
378  }
379  }
380  }
381 
382  template<typename Other, typename Archive, typename... Type, typename... Member>
383  void assign(Archive &archive, [[maybe_unused]] Member Type:: *... member) {
384  typename traits_type::entity_type length{};
385  archive(length);
386 
387  entity_type entt{};
388 
389  if constexpr(std::tuple_size_v<decltype(reg->template view<Other>().get({}))> == 0) {
390  while(length--) {
391  archive(entt);
392  restore(entt);
393  reg->template emplace_or_replace<Other>(map(entt));
394  }
395  } else {
396  Other instance{};
397 
398  while(length--) {
399  archive(entt, instance);
400  (update(instance, member), ...);
401  restore(entt);
402  reg->template emplace_or_replace<Other>(map(entt), std::move(instance));
403  }
404  }
405  }
406 
407 public:
409  using entity_type = Entity;
410 
416  : reg{&source}
417  {}
418 
421 
424 
435  template<typename Archive>
436  basic_continuous_loader & entities(Archive &archive) {
437  typename traits_type::entity_type length{};
438  entity_type entt{};
439 
440  archive(length);
441 
442  for(decltype(length) pos{}; pos < length; ++pos) {
443  archive(entt);
444 
445  if(const auto entity = (to_integral(entt) & traits_type::entity_mask); entity == pos) {
446  restore(entt);
447  } else {
448  destroy(entt);
449  }
450  }
451 
452  // discards the head of the list of destroyed entities
453  archive(entt);
454 
455  return *this;
456  }
457 
477  template<typename... Component, typename Archive, typename... Type, typename... Member>
478  basic_continuous_loader & component(Archive &archive, Member Type:: *... member) {
479  (remove_if_exists<Component>(), ...);
480  (assign<Component>(archive, member...), ...);
481  return *this;
482  }
483 
493  auto it = remloc.begin();
494 
495  while(it != remloc.cend()) {
496  const auto local = it->second.first;
497  bool &dirty = it->second.second;
498 
499  if(dirty) {
500  dirty = false;
501  ++it;
502  } else {
503  if(reg->valid(local)) {
504  reg->destroy(local);
505  }
506 
507  it = remloc.erase(it);
508  }
509  }
510 
511  return *this;
512  }
513 
525  reg->orphans([this](const auto entt) {
526  reg->destroy(entt);
527  });
528 
529  return *this;
530  }
531 
537  [[nodiscard]] bool contains(entity_type entt) const ENTT_NOEXCEPT {
538  return (remloc.find(entt) != remloc.cend());
539  }
540 
546  [[nodiscard]] entity_type map(entity_type entt) const ENTT_NOEXCEPT {
547  const auto it = remloc.find(entt);
548  entity_type other = null;
549 
550  if(it != remloc.cend()) {
551  other = it->second.first;
552  }
553 
554  return other;
555  }
556 
557 private:
558  std::unordered_map<entity_type, std::pair<entity_type, bool>> remloc;
560 };
561 
562 
563 }
564 
565 
566 #endif
entt::basic_continuous_loader::entity_type
Entity entity_type
Underlying entity identifier.
Definition: snapshot.hpp:409
entt::basic_registry::create
entity_type create()
Creates a new entity and returns it.
Definition: registry.hpp:443
entt::basic_registry::data
const entity_type * data() const
Direct access to the list of entities of a given pool.
Definition: registry.hpp:355
entt::basic_snapshot
Utility class to create snapshots from a registry.
Definition: snapshot.hpp:34
entt::to_integral
constexpr auto to_integral(const Entity entity) noexcept
Converts an entity type to its underlying type.
Definition: entity.hpp:93
entt::basic_snapshot::component
const basic_snapshot & component(Archive &archive) const
Puts aside the given components.
Definition: snapshot.hpp:119
entt::basic_snapshot_loader::basic_snapshot_loader
basic_snapshot_loader(basic_registry< entity_type > &source) noexcept
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:197
entt::basic_registry::assign
void assign(It first, It last, const entity_type destroyed)
Assigns entities to an empty registry.
Definition: registry.hpp:520
entt::basic_continuous_loader::basic_continuous_loader
basic_continuous_loader(basic_continuous_loader &&)=default
Default move constructor.
entt::basic_snapshot_loader::entities
const basic_snapshot_loader & entities(Archive &archive) const
Restores entities that were in use during serialization.
Definition: snapshot.hpp:221
entt::basic_snapshot::basic_snapshot
basic_snapshot(basic_snapshot &&)=default
Default move constructor.
entt::basic_registry::destroy
void destroy(const entity_type entity)
Destroys an entity.
Definition: registry.hpp:536
entt::basic_registry::size
size_type size() const
Returns the number of existing components of the given type.
Definition: registry.hpp:204
entt::basic_registry::empty
bool empty() const
Checks whether the registry or the pools of the given components are empty.
Definition: registry.hpp:304
entt::basic_snapshot_loader::basic_snapshot_loader
basic_snapshot_loader(basic_snapshot_loader &&)=default
Default move constructor.
entt::basic_continuous_loader::entities
basic_continuous_loader & entities(Archive &archive)
Restores entities that were in use during serialization.
Definition: snapshot.hpp:436
entt::basic_continuous_loader::contains
bool contains(entity_type entt) const noexcept
Tests if a loader knows about a given entity.
Definition: snapshot.hpp:537
entt::basic_registry::orphans
void orphans(Func func) const
Iterates orphans and applies them the given function object.
Definition: registry.hpp:1018
entt::basic_snapshot::entity_type
Entity entity_type
Underlying entity identifier.
Definition: snapshot.hpp:66
entt
EnTT default namespace.
Definition: algorithm.hpp:13
entt::basic_snapshot::operator=
basic_snapshot & operator=(basic_snapshot &&)=default
Default move assignment operator.
entt::basic_continuous_loader::basic_continuous_loader
basic_continuous_loader(basic_registry< entity_type > &source) noexcept
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:415
entt::basic_snapshot::component
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:139
entt::basic_continuous_loader::orphans
basic_continuous_loader & orphans()
Destroys those entities that have no components.
Definition: snapshot.hpp:524
entt::basic_continuous_loader::operator=
basic_continuous_loader & operator=(basic_continuous_loader &&)=default
Default move assignment operator.
entt::basic_continuous_loader::map
entity_type map(entity_type entt) const noexcept
Returns the identifier to which an entity refers.
Definition: snapshot.hpp:546
entt::basic_snapshot_loader::operator=
basic_snapshot_loader & operator=(basic_snapshot_loader &&)=default
Default move assignment operator.
entt::basic_snapshot_loader::orphans
const basic_snapshot_loader & orphans() const
Destroys those entities that have no components.
Definition: snapshot.hpp:268
entt::basic_continuous_loader::shrink
basic_continuous_loader & shrink()
Helps to purge entities that no longer have a conterpart.
Definition: snapshot.hpp:492
entt::basic_continuous_loader
Utility class for continuous loading.
Definition: snapshot.hpp:298
entt::basic_registry::destroyed
entity_type destroyed() const noexcept
Returns the head of the list of destroyed entities.
Definition: registry.hpp:384
entt::basic_registry< entity_type >
entt::entt_traits
Entity traits.
Definition: entity.hpp:21
entt::basic_continuous_loader::component
basic_continuous_loader & component(Archive &archive, Member Type::*... member)
Restores components and assigns them to the right entities.
Definition: snapshot.hpp:478
entt::basic_registry::valid
bool valid(const entity_type entity) const
Checks if an entity identifier refers to a valid entity.
Definition: registry.hpp:393
entt::basic_view
View.
Definition: fwd.hpp:24
entt::entity
entity
Default entity identifier.
Definition: fwd.hpp:60
entt::basic_snapshot::entities
const basic_snapshot & entities(Archive &archive) const
Puts aside all the entities from the underlying registry.
Definition: snapshot.hpp:93
entt::basic_snapshot_loader::component
const basic_snapshot_loader & component(Archive &archive) const
Restores components and assigns them to the right entities.
Definition: snapshot.hpp:253
entt::basic_snapshot_loader::entity_type
Entity entity_type
Underlying entity identifier.
Definition: snapshot.hpp:191
entt::basic_snapshot::basic_snapshot
basic_snapshot(const basic_registry< entity_type > &source) noexcept
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:72
entt::basic_snapshot_loader
Utility class to restore a snapshot as a whole.
Definition: snapshot.hpp:160