EnTT 3.14.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
20namespace internal {
21
22template<typename Registry>
23void orphans(Registry &registry) {
24 auto &storage = registry.template storage<typename Registry::entity_type>();
25
26 for(auto entt: storage) {
27 if(registry.orphan(entt)) {
28 storage.erase(entt);
29 }
30 }
31}
32
33} // namespace internal
46template<typename Registry>
48 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
50
51public:
55 using entity_type = typename registry_type::entity_type;
56
63
65 basic_snapshot(const basic_snapshot &) = delete;
66
69
72
78
84
94 const basic_snapshot &get(Archive &archive, const id_type id = type_hash<Type>::value()) const {
95 if(const auto *storage = reg->template storage<Type>(id); storage) {
96 const typename registry_type::common_type &base = *storage;
97
99
100 if constexpr(std::is_same_v<Type, entity_type>) {
102
103 for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) {
104 archive(*first);
105 }
106 } else if constexpr(registry_type::template storage_for_type<Type>::storage_policy == deletion_policy::in_place) {
107 for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) {
108 if(const auto entt = *it; entt == tombstone) {
109 archive(static_cast<entity_type>(null));
110 } else {
111 archive(entt);
112 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
113 }
114 }
115 } else {
116 for(auto elem: storage->reach()) {
117 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
118 }
119 }
120 } else {
122 }
123
124 return *this;
125 }
126
139 template<typename Type, typename Archive, typename It>
140 const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
141 static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
142
143 if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
144 archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
145
146 for(; first != last; ++first) {
147 if(const auto entt = *first; storage->contains(entt)) {
148 archive(entt);
149 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
150 } else {
151 archive(static_cast<entity_type>(null));
152 }
153 }
154 } else {
156 }
157
158 return *this;
159 }
160
161private:
162 const registry_type *reg;
163};
164
175template<typename Registry>
177 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
179
180public:
184 using entity_type = typename registry_type::entity_type;
185
191 : reg{&source} {
192 // restoring a snapshot as a whole requires a clean registry
193 ENTT_ASSERT(reg->template storage<entity_type>().free_list() == 0u, "Registry must be empty");
194 }
195
198
201
204
210
216
227 auto &storage = reg->template storage<Type>(id);
228 typename traits_type::entity_type length{};
229
230 archive(length);
231
232 if constexpr(std::is_same_v<Type, entity_type>) {
233 typename traits_type::entity_type count{};
234
235 storage.reserve(length);
236 archive(count);
237
238 for(entity_type entity = null; length; --length) {
241 }
242
243 storage.free_list(count);
244 } else {
245 auto &other = reg->template storage<entity_type>();
247
248 while(length--) {
249 if(archive(entt); entt != null) {
250 const auto entity = other.contains(entt) ? entt : other.emplace(entt);
251 ENTT_ASSERT(entity == entt, "Entity not available for use");
252
253 if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
255 } else {
256 Type elem{};
257 archive(elem);
258 storage.emplace(entity, std::move(elem));
259 }
260 }
261 }
262 }
263
264 return *this;
265 }
266
278 internal::orphans(*reg);
279 return *this;
280 }
281
282private:
283 registry_type *reg;
284};
285
302template<typename Registry>
304 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
306
307 void restore(typename Registry::entity_type entt) {
308 if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
309 if(!reg->valid(remloc[entity].second)) {
310 remloc[entity].second = reg->create();
311 }
312 } else {
313 remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
314 }
315 }
316
317 template<typename Container>
318 auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
319 // map like container
321
322 for(auto &&pair: container) {
323 using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
324 using second_type = typename std::decay_t<decltype(pair)>::second_type;
325
326 if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
327 other.emplace(map(pair.first), map(pair.second));
328 } else if constexpr(std::is_same_v<first_type, entity_type>) {
329 other.emplace(map(pair.first), std::move(pair.second));
330 } else {
331 static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
332 other.emplace(std::move(pair.first), map(pair.second));
333 }
334 }
335
336 using std::swap;
338 }
339
340 template<typename Container>
341 auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
342 // vector like container
343 static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
344
345 for(auto &&entt: container) {
346 entt = map(entt);
347 }
348 }
349
350 template<typename Component, typename Other, typename Member>
351 void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
352 if constexpr(!std::is_same_v<Component, Other>) {
353 return;
354 } else if constexpr(std::is_same_v<Member, entity_type>) {
355 instance.*member = map(instance.*member);
356 } else {
357 // maybe a container? let's try...
358 update(0, instance.*member);
359 }
360 }
361
362public:
366 using entity_type = typename registry_type::entity_type;
367
373 : remloc{source.get_allocator()},
374 reg{&source} {}
375
378
381
384
390
396
413 auto &storage = reg->template storage<Type>(id);
414 typename traits_type::entity_type length{};
416
417 archive(length);
418
419 if constexpr(std::is_same_v<Type, entity_type>) {
421
422 storage.reserve(length);
424
425 for(std::size_t pos{}; pos < in_use; ++pos) {
426 archive(entt);
427 restore(entt);
428 }
429
430 for(std::size_t pos = in_use; pos < length; ++pos) {
431 archive(entt);
432
433 if(const auto entity = to_entity(entt); remloc.contains(entity)) {
434 if(reg->valid(remloc[entity].second)) {
435 reg->destroy(remloc[entity].second);
436 }
437
438 remloc.erase(entity);
439 }
440 }
441 } else {
442 for(auto &&ref: remloc) {
443 storage.remove(ref.second.second);
444 }
445
446 while(length--) {
447 if(archive(entt); entt != null) {
448 restore(entt);
449
450 if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
452 } else {
453 Type elem{};
454 archive(elem);
455 storage.emplace(map(entt), std::move(elem));
456 }
457 }
458 }
459 }
460
461 return *this;
462 }
463
475 internal::orphans(*reg);
476 return *this;
477 }
478
484 [[nodiscard]] bool contains(entity_type entt) const noexcept {
485 const auto it = remloc.find(to_entity(entt));
486 return it != remloc.cend() && it->second.first == entt;
487 }
488
495 if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) {
496 return it->second.second;
497 }
498
499 return null;
500 }
501
502private:
504 registry_type *reg;
505};
506
507} // namespace entt
508
509#endif
Utility class for continuous loading.
Definition snapshot.hpp:303
basic_continuous_loader(const basic_continuous_loader &)=delete
Default copy constructor, deleted on purpose.
basic_continuous_loader(registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition snapshot.hpp:372
basic_continuous_loader(basic_continuous_loader &&) noexcept=default
Default move constructor.
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition snapshot.hpp:366
bool contains(entity_type entt) const noexcept
Tests if a loader knows about a given entity.
Definition snapshot.hpp:484
entity_type map(entity_type entt) const noexcept
Returns the identifier to which an entity refers.
Definition snapshot.hpp:494
basic_continuous_loader & orphans()
Destroys those entities that have no elements.
Definition snapshot.hpp:474
typename Traits::entity_type entity_type
Underlying entity type.
Definition entity.hpp:71
Utility class to restore a snapshot as a whole.
Definition snapshot.hpp:176
basic_snapshot_loader(registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition snapshot.hpp:190
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition snapshot.hpp:184
basic_snapshot_loader(basic_snapshot_loader &&) noexcept=default
Default move constructor.
basic_snapshot_loader & orphans()
Destroys those entities that have no elements.
Definition snapshot.hpp:277
basic_snapshot_loader(const basic_snapshot_loader &)=delete
Default copy constructor, deleted on purpose.
Utility class to create snapshots from a registry.
Definition snapshot.hpp:47
basic_snapshot(const registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition snapshot.hpp:61
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition snapshot.hpp:55
basic_snapshot(const basic_snapshot &)=delete
Default copy constructor, deleted on purpose.
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:140
basic_snapshot(basic_snapshot &&) noexcept=default
Default move constructor.
size_type size() const noexcept
Returns the number of elements in a sparse set.
bool contains(const entity_type entt) const noexcept
Checks if a sparse set contains an entity.
size_type free_list() const noexcept
Returns data on the free list whose meaning depends on the mode.
bool empty() const noexcept
Checks whether a sparse set is empty.
bool remove(const entity_type entt)
Removes an entity from a sparse set if it exists.
Storage implementation.
Definition storage.hpp:230
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:769
void reserve(const size_type cap) override
Increases the capacity of a storage.
Definition storage.hpp:512
value_type & emplace(const entity_type entt, Args &&...args)
Assigns an entity to a storage and constructs its object.
Definition storage.hpp:675
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:653
Associative container for key-value pairs with unique keys.
bool contains(const key_type &key) const
Checks if the container contains an element with a given key.
const_iterator cend() const noexcept
Returns an iterator to the end.
iterator find(const key_type &key)
Finds an element with a given key.
iterator erase(const_iterator pos)
Removes an element from a given position.
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.
EnTT default namespace.
Definition dense_map.hpp:22
entity
Default entity identifier.
Definition fwd.hpp:14
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:188
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:219
constexpr null_t null
Compile-time constant for null entities.
Definition entity.hpp:375
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition entity.hpp:384
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:14
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 elements.
Definition fwd.hpp:168
basic_registry<> registry
Alias declaration for the most common use case.
Definition fwd.hpp:93
@ in_place
In-place deletion policy.
@ ref
Aliasing mode, the object points to a non-const element.
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:76
Entity traits.
Definition entity.hpp:163
Type hash.
Definition type_info.hpp:92