EnTT 3.12.0
Loading...
Searching...
No Matches
snapshot.hpp
1#ifndef ENTT_ENTITY_SNAPSHOT_HPP
2#define ENTT_ENTITY_SNAPSHOT_HPP
3
4#include <cstddef>
5#include <iterator>
6#include <tuple>
7#include <type_traits>
8#include <utility>
9#include <vector>
10#include "../config/config.h"
11#include "../container/dense_map.hpp"
12#include "../core/type_traits.hpp"
13#include "entity.hpp"
14#include "fwd.hpp"
15#include "view.hpp"
16
17namespace entt {
18
24namespace internal {
25
26template<typename Registry>
27void orphans(Registry &registry) {
28 auto view = registry.template view<typename Registry::entity_type>();
29
30 for(auto entt: view) {
31 if(registry.orphan(entt)) {
32 view.storage()->erase(entt);
33 }
34 }
35}
36
37} // namespace internal
38
54template<typename Registry>
56 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
57 using traits_type = typename Registry::traits_type;
58
59public:
61 using registry_type = Registry;
63 using entity_type = typename registry_type::entity_type;
64
69 basic_snapshot(const registry_type &source) noexcept
70 : reg{&source} {}
71
73 basic_snapshot(basic_snapshot &&) noexcept = default;
74
76 basic_snapshot &operator=(basic_snapshot &&) noexcept = default;
77
86 template<typename Type, typename Archive>
87 const basic_snapshot &get(Archive &archive, const id_type id = type_hash<Type>::value()) const {
88 if(const auto *storage = reg->template storage<Type>(id); storage) {
89 archive(static_cast<typename traits_type::entity_type>(storage->size()));
90
91 if constexpr(std::is_same_v<Type, entity_type>) {
92 archive(static_cast<typename traits_type::entity_type>(storage->in_use()));
93
94 for(auto first = storage->data(), last = first + storage->size(); first != last; ++first) {
95 archive(*first);
96 }
97 } else {
98 for(auto elem: storage->reach()) {
99 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
100 }
101 }
102 } else {
103 archive(typename traits_type::entity_type{});
104 }
105
106 return *this;
107 }
108
121 template<typename Type, typename Archive, typename It>
122 const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
123 static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
124
125 if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
126 archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
127
128 for(; first != last; ++first) {
129 if(const auto entt = *first; storage->contains(entt)) {
130 archive(entt);
131 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
132 } else {
133 archive(static_cast<entity_type>(null));
134 }
135 }
136 } else {
137 archive(typename traits_type::entity_type{});
138 }
139
140 return *this;
141 }
142
149 template<typename Archive>
150 [[deprecated("use .get<Entity>(archive) instead")]] const basic_snapshot &entities(Archive &archive) const {
151 return get<entity_type>(archive);
152 }
153
161 template<typename... Component, typename Archive>
162 [[deprecated("use .get<Type>(archive) instead")]] const basic_snapshot &component(Archive &archive) const {
163 return (get<Component>(archive), ...);
164 }
165
177 template<typename... Component, typename Archive, typename It>
178 [[deprecated("use .get<Type>(archive, first, last) instead")]] const basic_snapshot &component(Archive &archive, It first, It last) const {
179 return (get<Component>(archive, first, last), ...);
180 }
181
182private:
183 const registry_type *reg;
184};
185
196template<typename Registry>
198 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
199 using traits_type = typename Registry::traits_type;
200
201public:
203 using registry_type = Registry;
205 using entity_type = typename registry_type::entity_type;
206
212 : reg{&source} {
213 // restoring a snapshot as a whole requires a clean registry
214 ENTT_ASSERT(reg->empty(), "Registry must be empty");
215 }
216
219
221 basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default;
222
231 template<typename Type, typename Archive>
232 basic_snapshot_loader &get([[maybe_unused]] Archive &archive, const id_type id = type_hash<Type>::value()) {
233 auto &storage = reg->template storage<Type>(id);
234 typename traits_type::entity_type length{};
235
236 archive(length);
237
238 if constexpr(std::is_same_v<Type, entity_type>) {
239 typename traits_type::entity_type in_use{};
240
241 storage.reserve(length);
242 archive(in_use);
243
244 for(entity_type entity = null; length; --length) {
245 archive(entity);
247 }
248
249 storage.in_use(in_use);
250 } else {
251 auto &other = reg->template storage<entity_type>();
253
254 while(length--) {
255 if(archive(entt); entt != null) {
256 const auto entity = other.contains(entt) ? entt : other.emplace(entt);
257 ENTT_ASSERT(entity == entt, "Entity not available for use");
258
259 if constexpr(Registry::template storage_for_type<Type>::traits_type::page_size == 0u) {
261 } else {
262 archive(storage.emplace(entity));
263 }
264 }
265 }
266 }
267
268 return *this;
269 }
270
277 template<typename Archive>
278 [[deprecated("use .get<Entity>(archive) instead")]] basic_snapshot_loader &entities(Archive &archive) {
279 return get<entity_type>(archive);
280 }
281
293 template<typename... Component, typename Archive>
294 [[deprecated("use .get<Type>(archive) instead")]] basic_snapshot_loader &component(Archive &archive) {
295 return (get<Component>(archive), ...);
296 }
297
309 internal::orphans(*reg);
310 return *this;
311 }
312
313private:
314 registry_type *reg;
315};
316
333template<typename Registry>
335 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
336 using traits_type = typename Registry::traits_type;
337
338 void restore(typename Registry::entity_type entt) {
339 if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
340 if(!reg->valid(remloc[entity].second)) {
341 remloc[entity].second = reg->create();
342 }
343 } else {
344 remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
345 }
346 }
347
348 template<typename Container>
349 auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
350 // map like container
351 Container other;
352
353 for(auto &&pair: container) {
354 using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
355 using second_type = typename std::decay_t<decltype(pair)>::second_type;
356
357 if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
358 other.emplace(map(pair.first), map(pair.second));
359 } else if constexpr(std::is_same_v<first_type, entity_type>) {
360 other.emplace(map(pair.first), std::move(pair.second));
361 } else {
362 static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
363 other.emplace(std::move(pair.first), map(pair.second));
364 }
365 }
366
367 using std::swap;
368 swap(container, other);
369 }
370
371 template<typename Container>
372 auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
373 // vector like container
374 static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
375
376 for(auto &&entt: container) {
377 entt = map(entt);
378 }
379 }
380
381 template<typename Component, typename Other, typename Member>
382 void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
383 if constexpr(!std::is_same_v<Component, Other>) {
384 return;
385 } else if constexpr(std::is_same_v<Member, entity_type>) {
386 instance.*member = map(instance.*member);
387 } else {
388 // maybe a container? let's try...
389 update(0, instance.*member);
390 }
391 }
392
393public:
395 using registry_type = Registry;
397 using entity_type = typename registry_type::entity_type;
398
404 : remloc{source.get_allocator()},
405 reg{&source} {}
406
409
412
427 template<typename Type, typename Archive>
428 basic_continuous_loader &get([[maybe_unused]] Archive &archive, const id_type id = type_hash<Type>::value()) {
429 auto &storage = reg->template storage<Type>(id);
430 typename traits_type::entity_type length{};
432
433 archive(length);
434
435 if constexpr(std::is_same_v<Type, entity_type>) {
436 typename traits_type::entity_type in_use{};
437
438 storage.reserve(length);
439 archive(in_use);
440
441 for(std::size_t pos{}; pos < in_use; ++pos) {
442 archive(entt);
443 restore(entt);
444 }
445
446 for(std::size_t pos = in_use; pos < length; ++pos) {
447 archive(entt);
448
449 if(const auto entity = to_entity(entt); remloc.contains(entity)) {
450 if(reg->valid(remloc[entity].second)) {
451 reg->destroy(remloc[entity].second);
452 }
453
454 remloc.erase(entity);
455 }
456 }
457 } else {
458 for(auto &&ref: remloc) {
459 storage.remove(ref.second.second);
460 }
461
462 while(length--) {
463 if(archive(entt); entt != null) {
464 restore(entt);
465
466 if constexpr(Registry::template storage_for_type<Type>::traits_type::page_size == 0u) {
468 } else {
469 archive(storage.emplace(map(entt)));
470 }
471 }
472 }
473 }
474
475 return *this;
476 }
477
487 template<typename Archive>
488 [[deprecated("use .get<Entity>(archive) instead")]] basic_continuous_loader &entities(Archive &archive) {
489 return get<entity_type>(archive);
490 }
491
507 template<typename... Component, typename Archive, typename... Member, typename... Clazz>
508 [[deprecated("use .component<Type>(archive, members...) instead")]] basic_continuous_loader &component(Archive &archive, Member Clazz::*...member) {
509 ([&](auto &storage) {
510 for(auto &&ref: remloc) {
511 storage.remove(ref.second.second);
512 }
513
514 typename traits_type::entity_type length{};
516
517 archive(length);
518
519 while(length--) {
520 if(archive(entt); entt != null) {
521 restore(entt);
522
523 if constexpr(std::remove_reference_t<decltype(storage)>::traits_type::page_size == 0u) {
525 } else {
526 auto &elem = storage.emplace(map(entt));
527 archive(elem);
528 (update(elem, member), ...);
529 }
530 }
531 }
532 }(reg->template storage<Component>()),
533 ...);
534
535 return *this;
536 }
537
546 [[deprecated("use .get<Entity>(archive) instead")]] basic_continuous_loader &shrink() {
547 return *this;
548 }
549
561 internal::orphans(*reg);
562 return *this;
563 }
564
570 [[nodiscard]] bool contains(entity_type entt) const noexcept {
571 const auto it = remloc.find(to_entity(entt));
572 return it != remloc.cend() && it->second.first == entt;
573 }
574
580 [[nodiscard]] entity_type map(entity_type entt) const noexcept {
581 if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) {
582 return it->second.second;
583 }
584
585 return null;
586 }
587
588private:
590 registry_type *reg;
591};
592
593} // namespace entt
594
595#endif
Utility class for continuous loading.
Definition: snapshot.hpp:334
basic_continuous_loader & operator=(basic_continuous_loader &&)=default
Default move assignment operator.
basic_continuous_loader & shrink()
Helps to purge entities that no longer have a counterpart.
Definition: snapshot.hpp:546
basic_continuous_loader(basic_continuous_loader &&)=default
Default move constructor.
basic_continuous_loader(registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:403
basic_continuous_loader & component(Archive &archive, Member Clazz::*...member)
Serializes all elements of a type with associated identifiers.
Definition: snapshot.hpp:508
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition: snapshot.hpp:397
bool contains(entity_type entt) const noexcept
Tests if a loader knows about a given entity.
Definition: snapshot.hpp:570
entity_type map(entity_type entt) const noexcept
Returns the identifier to which an entity refers.
Definition: snapshot.hpp:580
basic_continuous_loader & get(Archive &archive, const id_type id=type_hash< Type >::value())
Restores all elements of a type with associated identifiers.
Definition: snapshot.hpp:428
basic_continuous_loader & entities(Archive &archive)
Restores all identifiers, including those to be recycled.
Definition: snapshot.hpp:488
basic_continuous_loader & orphans()
Destroys those entities that have no components.
Definition: snapshot.hpp:560
Utility class to restore a snapshot as a whole.
Definition: snapshot.hpp:197
basic_snapshot_loader & component(Archive &archive)
Restores all elements of a type with associated identifiers.
Definition: snapshot.hpp:294
basic_snapshot_loader & entities(Archive &archive)
Restores all identifiers, including those to be recycled.
Definition: snapshot.hpp:278
basic_snapshot_loader(registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:211
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition: snapshot.hpp:205
basic_snapshot_loader(basic_snapshot_loader &&) noexcept=default
Default move constructor.
basic_snapshot_loader & orphans()
Destroys those entities that have no components.
Definition: snapshot.hpp:308
Utility class to create snapshots from a registry.
Definition: snapshot.hpp:55
basic_snapshot(const registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition: snapshot.hpp:69
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition: snapshot.hpp:63
Registry registry_type
Definition: snapshot.hpp:61
const basic_snapshot & component(Archive &archive, It first, It last) const
Serializes all elements of a type with associated identifiers for the entities in a range.
Definition: snapshot.hpp:178
const basic_snapshot & entities(Archive &archive) const
Serializes all identifiers, including those to be recycled.
Definition: snapshot.hpp:150
const basic_snapshot & component(Archive &archive) const
Serializes all elements of a type with associated identifiers.
Definition: snapshot.hpp:162
const basic_snapshot & get(Archive &archive, It first, It last, const id_type id=type_hash< Type >::value()) const
Serializes all elements of a type with associated identifiers for the entities in a range.
Definition: snapshot.hpp:122
basic_snapshot(basic_snapshot &&) noexcept=default
Default move constructor.
pointer data() const noexcept
Direct access to the internal packed array.
Definition: sparse_set.hpp:534
size_type size() const noexcept
Returns the number of elements in a sparse set.
Definition: sparse_set.hpp:510
bool contains(const entity_type entt) const noexcept
Checks if a sparse set contains an entity.
Definition: sparse_set.hpp:617
bool empty() const noexcept
Checks whether a sparse set is empty.
Definition: sparse_set.hpp:518
bool remove(const entity_type entt)
Removes an entity from a sparse set if it exists.
Definition: sparse_set.hpp:784
Basic storage implementation.
Definition: storage.hpp:236
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
Definition: storage.hpp:765
void reserve(const size_type cap) override
Increases the capacity of a storage.
Definition: storage.hpp:508
value_type & emplace(const entity_type entt, Args &&...args)
Assigns an entity to a storage and constructs its object.
Definition: storage.hpp:671
std::tuple< const value_type & > get_as_tuple(const entity_type entt) const noexcept
Returns the object assigned to an entity as a tuple.
Definition: storage.hpp:649
Associative container for key-value pairs with unique keys.
Definition: dense_map.hpp:264
bool contains(const key_type &key) const
Checks if the container contains an element with a given key.
Definition: dense_map.hpp:847
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: dense_map.hpp:490
iterator find(const key_type &key)
Finds an element with a given key.
Definition: dense_map.hpp:772
iterator erase(const_iterator pos)
Removes an element from a given position.
Definition: dense_map.hpp:658
std::pair< iterator, bool > insert_or_assign(const key_type &key, Arg &&value)
Inserts an element into the container or assigns to the current element if the key already exists.
Definition: dense_map.hpp:584
EnTT default namespace.
Definition: dense_map.hpp:21
entity
Default entity identifier.
Definition: fwd.hpp:13
constexpr entt_traits< Entity >::entity_type to_entity(const Entity value) noexcept
Returns the entity part once converted to the underlying type.
Definition: entity.hpp:186
std::uint32_t id_type
Alias declaration for type identifiers.
Definition: fwd.hpp:13
constexpr null_t null
Compile-time constant for null entities.
Definition: entity.hpp:366
basic_view< type_list_transform_t< Get, storage_for >, type_list_transform_t< Exclude, storage_for > > view
Alias declaration for the most common use case.
Definition: fwd.hpp:238
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition: fwd.hpp:192
constexpr void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs)
Swaps two compressed pair objects.
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition: fwd.hpp:132
basic_registry<> registry
Alias declaration for the most common use case.
Definition: fwd.hpp:195
Type hash.
Definition: type_info.hpp:100