EnTT 4.0.0
Loading...
Searching...
No Matches
snapshot.hpp
1#ifndef ENTT_ENTITY_SNAPSHOT_HPP
2#define ENTT_ENTITY_SNAPSHOT_HPP
3
4#include "../config/config.h"
5#include "../container/dense_map.hpp"
6#include "../core/type_traits.hpp"
7#include "../stl/concepts.hpp"
8#include "../stl/cstddef.hpp"
9#include "../stl/iterator.hpp"
10#include "../stl/tuple.hpp"
11#include "../stl/type_traits.hpp"
12#include "../stl/utility.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 for(auto &storage = registry.template storage<typename Registry::entity_type>(); auto entt: storage) {
25 if(registry.orphan(entt)) {
26 storage.erase(entt);
27 }
28 }
29}
30
31} // namespace internal
33
44template<typename Registry>
46 static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
48
49public:
51 using registry_type = Registry;
54
59 basic_snapshot(const registry_type &source) noexcept
60 : reg{&source} {}
61
63 basic_snapshot(const basic_snapshot &) = delete;
64
66 basic_snapshot(basic_snapshot &&) noexcept = default;
67
69 ~basic_snapshot() = default;
70
75 basic_snapshot &operator=(const basic_snapshot &) = delete;
76
81 basic_snapshot &operator=(basic_snapshot &&) noexcept = default;
82
91 template<typename Type, typename Archive>
92 const basic_snapshot &get(Archive &archive, const id_type id = type_hash<Type>::value()) const {
93 if(const auto *storage = reg->template storage<Type>(id); storage) {
94 const typename registry_type::common_type &base = *storage;
95
96 archive(static_cast<traits_type::entity_type>(storage->size()));
97
98 if constexpr(stl::is_same_v<Type, entity_type>) {
99 archive(static_cast<traits_type::entity_type>(storage->free_list()));
100
101 for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) {
102 archive(*first);
103 }
104 } else if constexpr(registry_type::template storage_for_type<Type>::storage_policy == deletion_policy::in_place) {
105 for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) {
106 if(const auto entt = *it; entt == tombstone) {
107 archive(static_cast<entity_type>(null));
108 } else {
109 archive(entt);
110 stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
111 }
112 }
113 } else {
114 for(auto elem: storage->reach()) {
115 stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, elem);
116 }
117 }
118 } else {
119 archive(typename traits_type::entity_type{});
120 }
121
122 return *this;
123 }
124
136 template<typename Type, typename Archive>
137 const basic_snapshot &get(Archive &archive, stl::input_iterator auto first, stl::input_iterator auto last, const id_type id = type_hash<Type>::value()) const {
138 static_assert(!stl::is_same_v<Type, entity_type>, "Entity types not supported");
139
140 if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
141 archive(static_cast<traits_type::entity_type>(stl::distance(first, last)));
142
143 for(; first != last; ++first) {
144 if(const auto entt = *first; storage->contains(entt)) {
145 archive(entt);
146 stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
147 } else {
148 archive(static_cast<entity_type>(null));
149 }
150 }
151 } else {
152 archive(typename traits_type::entity_type{});
153 }
154
155 return *this;
156 }
157
158private:
159 const registry_type *reg;
160};
161
172template<typename Registry>
174 static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
176
177public:
179 using registry_type = Registry;
182
188 : reg{&source} {
189 // restoring a snapshot as a whole requires a clean registry
190 ENTT_ASSERT(reg->template storage<entity_type>().free_list() == 0u, "Registry must be empty");
191 }
192
195
198
201
206 basic_snapshot_loader &operator=(const basic_snapshot_loader &) = delete;
207
212 basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default;
213
222 template<typename Type, typename Archive>
223 basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
224 auto &storage = reg->template storage<Type>(id);
225 typename traits_type::entity_type length{};
226
227 archive(length);
228
229 if constexpr(stl::is_same_v<Type, entity_type>) {
230 typename traits_type::entity_type count{};
231 entity_type placeholder{};
232
233 storage.reserve(length);
234 archive(count);
235
236 for(entity_type entity = null; length; --length) {
237 archive(entity);
238 storage.generate(entity);
239 placeholder = (entity > placeholder) ? entity : placeholder;
240 }
241
242 storage.start_from(traits_type::next(placeholder));
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.generate(entt);
251 ENTT_ASSERT(entity == entt, "Entity not available for use");
252
253 if constexpr(stl::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
254 storage.emplace(entity);
255 } else {
256 Type elem{};
257 archive(elem);
258 storage.emplace(entity, stl::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(!stl::is_const_v<Registry>, "Non-const registry type required");
306
307 void restore(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, stl::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
320 Container other;
321
322 for(auto &&pair: container) {
323 using first_type = stl::remove_const_t<typename stl::decay_t<decltype(pair)>::first_type>;
324 using second_type = stl::decay_t<decltype(pair)>::second_type;
325
326 if constexpr(stl::is_same_v<first_type, entity_type> && stl::is_same_v<second_type, entity_type>) {
327 other.emplace(map(pair.first), map(pair.second));
328 } else if constexpr(stl::is_same_v<first_type, entity_type>) {
329 other.emplace(map(pair.first), stl::move(pair.second));
330 } else {
331 static_assert(stl::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
332 other.emplace(stl::move(pair.first), map(pair.second));
333 }
334 }
335
336 using stl::swap;
337 swap(container, other);
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(stl::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(!stl::is_same_v<Component, Other>) {
353 return;
354 } else if constexpr(stl::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:
364 using registry_type = Registry;
367
373 : remloc{source.get_allocator()},
374 reg{&source} {}
375
378
381
384
390
395 basic_continuous_loader &operator=(basic_continuous_loader &&) noexcept = default;
396
411 template<typename Type, typename Archive>
412 basic_continuous_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
413 auto &storage = reg->template storage<Type>(id);
414 typename traits_type::entity_type length{};
416
417 archive(length);
418
419 if constexpr(stl::is_same_v<Type, entity_type>) {
420 typename traits_type::entity_type in_use{};
421
422 storage.reserve(length);
423 archive(in_use);
424
425 for(stl::size_t pos{}; pos < in_use; ++pos) {
426 archive(entt);
427 restore(entt);
428 }
429
430 for(stl::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(stl::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
451 storage.emplace(map(entt));
452 } else {
453 Type elem{};
454 archive(elem);
455 storage.emplace(map(entt), stl::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
494 [[nodiscard]] entity_type map(entity_type entt) const noexcept {
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
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.
bool contains(entity_type entt) const noexcept
Tests if a loader knows about a given entity.
Definition snapshot.hpp:484
registry_type::entity_type entity_type
Definition snapshot.hpp:366
entity_type map(entity_type entt) const noexcept
Returns the identifier to which an entity refers.
Definition snapshot.hpp:494
basic_continuous_loader & get(Archive &archive, const id_type id=type_hash< Type >::value())
Definition snapshot.hpp:412
basic_continuous_loader & orphans()
Destroys those entities that have no elements.
Definition snapshot.hpp:474
static constexpr value_type next(const value_type value) noexcept
Definition entity.hpp:130
internal::entt_traits< Type >::entity_type entity_type
Definition entity.hpp:83
bool orphan(const entity_type entt) const
Checks if an entity has elements assigned.
Definition registry.hpp:940
traits_type::value_type entity_type
Definition registry.hpp:268
basic_snapshot_loader(registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition snapshot.hpp:187
basic_snapshot_loader & get(Archive &archive, const id_type id=type_hash< Type >::value())
Definition snapshot.hpp:223
basic_snapshot_loader(basic_snapshot_loader &&) noexcept=default
Default move constructor.
registry_type::entity_type entity_type
Definition snapshot.hpp:181
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.
basic_snapshot(const registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition snapshot.hpp:59
registry_type::entity_type entity_type
Definition snapshot.hpp:53
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:92
const basic_snapshot & get(Archive &archive, stl::input_iterator auto first, stl::input_iterator auto 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:137
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:25
entity
Default entity identifier.
Definition fwd.hpp:15
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:202
@ in_place
In-place deletion policy.
Definition fwd.hpp:22
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:299
basic_registry<> registry
Alias declaration for the most common use case.
Definition fwd.hpp:96
@ ref
Aliasing mode, non-const reference.
Definition fwd.hpp:19
stl::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:79
Entity traits.
Definition entity.hpp:177
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.