EnTT 3.13.2
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");
49 using traits_type = typename Registry::traits_type;
50
51public:
55 using entity_type = typename registry_type::entity_type;
56
63
66
69
79 const basic_snapshot &get(Archive &archive, const id_type id = type_hash<Type>::value()) const {
80 if(const auto *storage = reg->template storage<Type>(id); storage) {
81 archive(static_cast<typename traits_type::entity_type>(storage->size()));
82
83 if constexpr(std::is_same_v<Type, entity_type>) {
84 archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
85
86 for(auto first = storage->data(), last = first + storage->size(); first != last; ++first) {
87 archive(*first);
88 }
89 } else if constexpr(component_traits<Type>::in_place_delete) {
90 const typename registry_type::common_type &base = *storage;
91
92 for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) {
93 if(const auto entt = *it; entt == tombstone) {
94 archive(static_cast<entity_type>(null));
95 } else {
97 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
98 }
99 }
100 } else {
101 for(auto elem: storage->reach()) {
102 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
103 }
104 }
105 } else {
106 archive(typename traits_type::entity_type{});
107 }
108
109 return *this;
110 }
111
124 template<typename Type, typename Archive, typename It>
125 const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
126 static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
127
128 if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
129 archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
130
131 for(; first != last; ++first) {
132 if(const auto entt = *first; storage->contains(entt)) {
133 archive(entt);
134 std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
135 } else {
136 archive(static_cast<entity_type>(null));
137 }
138 }
139 } else {
140 archive(typename traits_type::entity_type{});
141 }
142
143 return *this;
144 }
145
146private:
147 const registry_type *reg;
148};
149
160template<typename Registry>
162 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
163 using traits_type = typename Registry::traits_type;
164
165public:
169 using entity_type = typename registry_type::entity_type;
170
176 : reg{&source} {
177 // restoring a snapshot as a whole requires a clean registry
178 ENTT_ASSERT(reg->template storage<entity_type>().free_list() == 0u, "Registry must be empty");
179 }
180
183
186
197 auto &storage = reg->template storage<Type>(id);
198 typename traits_type::entity_type length{};
199
200 archive(length);
201
202 if constexpr(std::is_same_v<Type, entity_type>) {
203 typename traits_type::entity_type count{};
204
205 storage.reserve(length);
206 archive(count);
207
208 for(entity_type entity = null; length; --length) {
211 }
212
213 storage.free_list(count);
214 } else {
215 auto &other = reg->template storage<entity_type>();
217
218 while(length--) {
219 if(archive(entt); entt != null) {
220 const auto entity = other.contains(entt) ? entt : other.emplace(entt);
221 ENTT_ASSERT(entity == entt, "Entity not available for use");
222
223 if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
225 } else {
226 Type elem{};
227 archive(elem);
228 storage.emplace(entity, std::move(elem));
229 }
230 }
231 }
232 }
233
234 return *this;
235 }
236
248 internal::orphans(*reg);
249 return *this;
250 }
251
252private:
253 registry_type *reg;
254};
255
272template<typename Registry>
274 static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
275 using traits_type = typename Registry::traits_type;
276
277 void restore(typename Registry::entity_type entt) {
278 if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
279 if(!reg->valid(remloc[entity].second)) {
280 remloc[entity].second = reg->create();
281 }
282 } else {
283 remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
284 }
285 }
286
287 template<typename Container>
288 auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
289 // map like container
291
292 for(auto &&pair: container) {
293 using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
294 using second_type = typename std::decay_t<decltype(pair)>::second_type;
295
296 if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
297 other.emplace(map(pair.first), map(pair.second));
298 } else if constexpr(std::is_same_v<first_type, entity_type>) {
299 other.emplace(map(pair.first), std::move(pair.second));
300 } else {
301 static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
302 other.emplace(std::move(pair.first), map(pair.second));
303 }
304 }
305
306 using std::swap;
308 }
309
310 template<typename Container>
311 auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
312 // vector like container
313 static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
314
315 for(auto &&entt: container) {
316 entt = map(entt);
317 }
318 }
319
320 template<typename Component, typename Other, typename Member>
321 void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
322 if constexpr(!std::is_same_v<Component, Other>) {
323 return;
324 } else if constexpr(std::is_same_v<Member, entity_type>) {
325 instance.*member = map(instance.*member);
326 } else {
327 // maybe a container? let's try...
328 update(0, instance.*member);
329 }
330 }
331
332public:
336 using entity_type = typename registry_type::entity_type;
337
343 : remloc{source.get_allocator()},
344 reg{&source} {}
345
348
351
366 template<typename Type, typename Archive>
368 auto &storage = reg->template storage<Type>(id);
369 typename traits_type::entity_type length{};
371
372 archive(length);
373
374 if constexpr(std::is_same_v<Type, entity_type>) {
375 typename traits_type::entity_type in_use{};
376
377 storage.reserve(length);
378 archive(in_use);
379
380 for(std::size_t pos{}; pos < in_use; ++pos) {
381 archive(entt);
382 restore(entt);
383 }
384
385 for(std::size_t pos = in_use; pos < length; ++pos) {
386 archive(entt);
387
388 if(const auto entity = to_entity(entt); remloc.contains(entity)) {
389 if(reg->valid(remloc[entity].second)) {
390 reg->destroy(remloc[entity].second);
391 }
392
393 remloc.erase(entity);
394 }
395 }
396 } else {
397 for(auto &&ref: remloc) {
398 storage.remove(ref.second.second);
399 }
400
401 while(length--) {
402 if(archive(entt); entt != null) {
403 restore(entt);
404
405 if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
407 } else {
408 Type elem{};
409 archive(elem);
410 storage.emplace(map(entt), std::move(elem));
411 }
412 }
413 }
414 }
415
416 return *this;
417 }
418
430 internal::orphans(*reg);
431 return *this;
432 }
433
439 [[nodiscard]] bool contains(entity_type entt) const noexcept {
440 const auto it = remloc.find(to_entity(entt));
441 return it != remloc.cend() && it->second.first == entt;
442 }
443
450 if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) {
451 return it->second.second;
452 }
453
454 return null;
455 }
456
457private:
459 registry_type *reg;
460};
461
462} // namespace entt
463
464#endif
Utility class for continuous loading.
Definition snapshot.hpp:273
basic_continuous_loader & operator=(basic_continuous_loader &&)=default
Default move assignment operator.
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:342
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition snapshot.hpp:336
bool contains(entity_type entt) const noexcept
Tests if a loader knows about a given entity.
Definition snapshot.hpp:439
entity_type map(entity_type entt) const noexcept
Returns the identifier to which an entity refers.
Definition snapshot.hpp:449
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:367
basic_continuous_loader & orphans()
Destroys those entities that have no components.
Definition snapshot.hpp:429
Utility class to restore a snapshot as a whole.
Definition snapshot.hpp:161
basic_snapshot_loader(registry_type &source) noexcept
Constructs an instance that is bound to a given registry.
Definition snapshot.hpp:175
typename registry_type::entity_type entity_type
Underlying entity identifier.
Definition snapshot.hpp:169
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:247
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
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:125
basic_snapshot(basic_snapshot &&) noexcept=default
Default move constructor.
pointer data() const noexcept
Direct access to the internal packed array.
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 the head of the free list, if any.
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.
Basic storage implementation.
Definition storage.hpp:229
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:757
void reserve(const size_type cap) override
Increases the capacity of a storage.
Definition storage.hpp:500
value_type & emplace(const entity_type entt, Args &&...args)
Assigns an entity to a storage and constructs its object.
Definition storage.hpp:663
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:641
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: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:181
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:258
constexpr null_t null
Compile-time constant for null entities.
Definition entity.hpp:363
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition entity.hpp:372
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:13
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:157
basic_registry<> registry
Alias declaration for the most common use case.
Definition fwd.hpp:82
@ 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:72
Common way to access various properties of components.
Definition component.hpp:42
Type hash.
Definition type_info.hpp:92