EnTT 3.15.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
35
46template<typename Registry>
48 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
50
51public:
53 using registry_type = Registry;
56
61 basic_snapshot(const registry_type &source) noexcept
62 : reg{&source} {}
63
65 basic_snapshot(const basic_snapshot &) = delete;
66
68 basic_snapshot(basic_snapshot &&) noexcept = default;
69
71 ~basic_snapshot() = default;
72
77 basic_snapshot &operator=(const basic_snapshot &) = delete;
78
83 basic_snapshot &operator=(basic_snapshot &&) noexcept = default;
84
93 template<typename Type, typename Archive>
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
98 archive(static_cast<typename traits_type::entity_type>(storage->size()));
99
100 if constexpr(std::is_same_v<Type, entity_type>) {
101 archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
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 {
121 archive(typename traits_type::entity_type{});
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 {
155 archive(typename traits_type::entity_type{});
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:
182 using registry_type = Registry;
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
209 basic_snapshot_loader &operator=(const basic_snapshot_loader &) = delete;
210
215 basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default;
216
225 template<typename Type, typename Archive>
226 basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
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 entity_type placeholder{};
235
236 storage.reserve(length);
237 archive(count);
238
239 for(entity_type entity = null; length; --length) {
240 archive(entity);
241 storage.generate(entity);
242 placeholder = (entity > placeholder) ? entity : placeholder;
243 }
244
245 storage.start_from(traits_type::next(placeholder));
246 storage.free_list(count);
247 } else {
248 auto &other = reg->template storage<entity_type>();
250
251 while(length--) {
252 if(archive(entt); entt != null) {
253 const auto entity = other.contains(entt) ? entt : other.generate(entt);
254 ENTT_ASSERT(entity == entt, "Entity not available for use");
255
256 if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
257 storage.emplace(entity);
258 } else {
259 Type elem{};
260 archive(elem);
261 storage.emplace(entity, std::move(elem));
262 }
263 }
264 }
265 }
266
267 return *this;
268 }
269
281 internal::orphans(*reg);
282 return *this;
283 }
284
285private:
286 registry_type *reg;
287};
288
305template<typename Registry>
307 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
309
310 void restore(typename Registry::entity_type entt) {
311 if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
312 if(!reg->valid(remloc[entity].second)) {
313 remloc[entity].second = reg->create();
314 }
315 } else {
316 remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
317 }
318 }
319
320 template<typename Container>
321 auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
322 // map like container
323 Container other;
324
325 for(auto &&pair: container) {
326 using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
327 using second_type = typename std::decay_t<decltype(pair)>::second_type;
328
329 if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
330 other.emplace(map(pair.first), map(pair.second));
331 } else if constexpr(std::is_same_v<first_type, entity_type>) {
332 other.emplace(map(pair.first), std::move(pair.second));
333 } else {
334 static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
335 other.emplace(std::move(pair.first), map(pair.second));
336 }
337 }
338
339 using std::swap;
340 swap(container, other);
341 }
342
343 template<typename Container>
344 auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
345 // vector like container
346 static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
347
348 for(auto &&entt: container) {
349 entt = map(entt);
350 }
351 }
352
353 template<typename Component, typename Other, typename Member>
354 void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
355 if constexpr(!std::is_same_v<Component, Other>) {
356 return;
357 } else if constexpr(std::is_same_v<Member, entity_type>) {
358 instance.*member = map(instance.*member);
359 } else {
360 // maybe a container? let's try...
361 update(0, instance.*member);
362 }
363 }
364
365public:
367 using registry_type = Registry;
370
376 : remloc{source.get_allocator()},
377 reg{&source} {}
378
381
384
387
393
398 basic_continuous_loader &operator=(basic_continuous_loader &&) noexcept = default;
399
414 template<typename Type, typename Archive>
415 basic_continuous_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
416 auto &storage = reg->template storage<Type>(id);
417 typename traits_type::entity_type length{};
419
420 archive(length);
421
422 if constexpr(std::is_same_v<Type, entity_type>) {
423 typename traits_type::entity_type in_use{};
424
425 storage.reserve(length);
426 archive(in_use);
427
428 for(std::size_t pos{}; pos < in_use; ++pos) {
429 archive(entt);
430 restore(entt);
431 }
432
433 for(std::size_t pos = in_use; pos < length; ++pos) {
434 archive(entt);
435
436 if(const auto entity = to_entity(entt); remloc.contains(entity)) {
437 if(reg->valid(remloc[entity].second)) {
438 reg->destroy(remloc[entity].second);
439 }
440
441 remloc.erase(entity);
442 }
443 }
444 } else {
445 for(auto &&ref: remloc) {
446 storage.remove(ref.second.second);
447 }
448
449 while(length--) {
450 if(archive(entt); entt != null) {
451 restore(entt);
452
453 if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
454 storage.emplace(map(entt));
455 } else {
456 Type elem{};
457 archive(elem);
458 storage.emplace(map(entt), std::move(elem));
459 }
460 }
461 }
462 }
463
464 return *this;
465 }
466
478 internal::orphans(*reg);
479 return *this;
480 }
481
487 [[nodiscard]] bool contains(entity_type entt) const noexcept {
488 const auto it = remloc.find(to_entity(entt));
489 return it != remloc.cend() && it->second.first == entt;
490 }
491
497 [[nodiscard]] entity_type map(entity_type entt) const noexcept {
498 if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) {
499 return it->second.second;
500 }
501
502 return null;
503 }
504
505private:
507 registry_type *reg;
508};
509
510} // namespace entt
511
512#endif
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:375
basic_continuous_loader(basic_continuous_loader &&) noexcept=default
Default move constructor.
typename registry_type::entity_type entity_type
Definition snapshot.hpp:369
bool contains(entity_type entt) const noexcept
Tests if a loader knows about a given entity.
Definition snapshot.hpp:487
entity_type map(entity_type entt) const noexcept
Returns the identifier to which an entity refers.
Definition snapshot.hpp:497
basic_continuous_loader & get(Archive &archive, const id_type id=type_hash< Type >::value())
Definition snapshot.hpp:415
basic_continuous_loader & orphans()
Destroys those entities that have no elements.
Definition snapshot.hpp:477
typename internal::entt_traits< Type >::entity_type entity_type
Definition entity.hpp:71
static constexpr value_type next(const value_type value) noexcept
Definition entity.hpp:116
bool orphan(const entity_type entt) const
Checks if an entity has elements assigned.
Definition registry.hpp:978
typename traits_type::value_type entity_type
Definition registry.hpp:304
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
Definition snapshot.hpp:184
basic_snapshot_loader & get(Archive &archive, const id_type id=type_hash< Type >::value())
Definition snapshot.hpp:226
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:280
basic_snapshot_loader(const basic_snapshot_loader &)=delete
Default copy constructor, deleted on purpose.
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
Definition snapshot.hpp:55
basic_snapshot(const basic_snapshot &)=delete
Default copy constructor, deleted on purpose.
const basic_snapshot & get(Archive &archive, const id_type id=type_hash< Type >::value()) const
Definition snapshot.hpp:94
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.
void erase(const entity_type entt)
Erases an entity from a sparse set.
Associative container for key-value pairs with unique keys.
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 void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs) noexcept
Swaps two compressed pair objects.
constexpr null_t null
Compile-time constant for null entities.
Definition entity.hpp:375
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
basic_registry<> registry
Alias declaration for the most common use case.
Definition fwd.hpp:95
@ in_place
In-place deletion policy.
Definition fwd.hpp:21
@ ref
Aliasing mode, the object points to a non-const element.
Definition fwd.hpp:19
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:78
Entity traits.
Definition entity.hpp:163
Type hash.
Definition type_info.hpp:92
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.