snapshot.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. #ifndef ENTT_ENTITY_SNAPSHOT_HPP
  2. #define ENTT_ENTITY_SNAPSHOT_HPP
  3. #include <cstddef>
  4. #include <iterator>
  5. #include <tuple>
  6. #include <type_traits>
  7. #include <utility>
  8. #include <vector>
  9. #include "../config/config.h"
  10. #include "../container/dense_map.hpp"
  11. #include "../core/type_traits.hpp"
  12. #include "entity.hpp"
  13. #include "fwd.hpp"
  14. #include "view.hpp"
  15. namespace entt {
  16. /**
  17. * @cond TURN_OFF_DOXYGEN
  18. * Internal details not to be documented.
  19. */
  20. namespace internal {
  21. template<typename Registry>
  22. void orphans(Registry &registry) {
  23. auto &storage = registry.template storage<typename Registry::entity_type>();
  24. for(auto entt: storage) {
  25. if(registry.orphan(entt)) {
  26. storage.erase(entt);
  27. }
  28. }
  29. }
  30. } // namespace internal
  31. /**
  32. * Internal details not to be documented.
  33. * @endcond
  34. */
  35. /**
  36. * @brief Utility class to create snapshots from a registry.
  37. *
  38. * A _snapshot_ can be either a dump of the entire registry or a narrower
  39. * selection of components of interest.<br/>
  40. * This type can be used in both cases if provided with a correctly configured
  41. * output archive.
  42. *
  43. * @tparam Registry Basic registry type.
  44. */
  45. template<typename Registry>
  46. class basic_snapshot {
  47. static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
  48. using traits_type = typename Registry::traits_type;
  49. public:
  50. /*! Basic registry type. */
  51. using registry_type = Registry;
  52. /*! @brief Underlying entity identifier. */
  53. using entity_type = typename registry_type::entity_type;
  54. /**
  55. * @brief Constructs an instance that is bound to a given registry.
  56. * @param source A valid reference to a registry.
  57. */
  58. basic_snapshot(const registry_type &source) noexcept
  59. : reg{&source} {}
  60. /*! @brief Default move constructor. */
  61. basic_snapshot(basic_snapshot &&) noexcept = default;
  62. /*! @brief Default move assignment operator. @return This snapshot. */
  63. basic_snapshot &operator=(basic_snapshot &&) noexcept = default;
  64. /**
  65. * @brief Serializes all elements of a type with associated identifiers.
  66. * @tparam Type Type of elements to serialize.
  67. * @tparam Archive Type of output archive.
  68. * @param archive A valid reference to an output archive.
  69. * @param id Optional name used to map the storage within the registry.
  70. * @return An object of this type to continue creating the snapshot.
  71. */
  72. template<typename Type, typename Archive>
  73. const basic_snapshot &get(Archive &archive, const id_type id = type_hash<Type>::value()) const {
  74. if(const auto *storage = reg->template storage<Type>(id); storage) {
  75. archive(static_cast<typename traits_type::entity_type>(storage->size()));
  76. if constexpr(std::is_same_v<Type, entity_type>) {
  77. archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
  78. for(auto first = storage->data(), last = first + storage->size(); first != last; ++first) {
  79. archive(*first);
  80. }
  81. } else {
  82. for(auto elem: storage->reach()) {
  83. std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
  84. }
  85. }
  86. } else {
  87. archive(typename traits_type::entity_type{});
  88. }
  89. return *this;
  90. }
  91. /**
  92. * @brief Serializes all elements of a type with associated identifiers for
  93. * the entities in a range.
  94. * @tparam Type Type of elements to serialize.
  95. * @tparam Archive Type of output archive.
  96. * @tparam It Type of input iterator.
  97. * @param archive A valid reference to an output archive.
  98. * @param first An iterator to the first element of the range to serialize.
  99. * @param last An iterator past the last element of the range to serialize.
  100. * @param id Optional name used to map the storage within the registry.
  101. * @return An object of this type to continue creating the snapshot.
  102. */
  103. template<typename Type, typename Archive, typename It>
  104. const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
  105. static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
  106. if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
  107. archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
  108. for(; first != last; ++first) {
  109. if(const auto entt = *first; storage->contains(entt)) {
  110. archive(entt);
  111. std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
  112. } else {
  113. archive(static_cast<entity_type>(null));
  114. }
  115. }
  116. } else {
  117. archive(typename traits_type::entity_type{});
  118. }
  119. return *this;
  120. }
  121. private:
  122. const registry_type *reg;
  123. };
  124. /**
  125. * @brief Utility class to restore a snapshot as a whole.
  126. *
  127. * A snapshot loader requires that the destination registry be empty and loads
  128. * all the data at once while keeping intact the identifiers that the entities
  129. * originally had.<br/>
  130. * An example of use is the implementation of a save/restore utility.
  131. *
  132. * @tparam Registry Basic registry type.
  133. */
  134. template<typename Registry>
  135. class basic_snapshot_loader {
  136. static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
  137. using traits_type = typename Registry::traits_type;
  138. public:
  139. /*! Basic registry type. */
  140. using registry_type = Registry;
  141. /*! @brief Underlying entity identifier. */
  142. using entity_type = typename registry_type::entity_type;
  143. /**
  144. * @brief Constructs an instance that is bound to a given registry.
  145. * @param source A valid reference to a registry.
  146. */
  147. basic_snapshot_loader(registry_type &source) noexcept
  148. : reg{&source} {
  149. // restoring a snapshot as a whole requires a clean registry
  150. ENTT_ASSERT(reg->template storage<entity_type>().empty() && (reg->storage().begin() == reg->storage().end()), "Registry must be empty");
  151. }
  152. /*! @brief Default move constructor. */
  153. basic_snapshot_loader(basic_snapshot_loader &&) noexcept = default;
  154. /*! @brief Default move assignment operator. @return This loader. */
  155. basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default;
  156. /**
  157. * @brief Restores all elements of a type with associated identifiers.
  158. * @tparam Type Type of elements to restore.
  159. * @tparam Archive Type of input archive.
  160. * @param archive A valid reference to an input archive.
  161. * @param id Optional name used to map the storage within the registry.
  162. * @return A valid loader to continue restoring data.
  163. */
  164. template<typename Type, typename Archive>
  165. basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
  166. auto &storage = reg->template storage<Type>(id);
  167. typename traits_type::entity_type length{};
  168. archive(length);
  169. if constexpr(std::is_same_v<Type, entity_type>) {
  170. typename traits_type::entity_type count{};
  171. storage.reserve(length);
  172. archive(count);
  173. for(entity_type entity = null; length; --length) {
  174. archive(entity);
  175. storage.emplace(entity);
  176. }
  177. storage.free_list(count);
  178. } else {
  179. auto &other = reg->template storage<entity_type>();
  180. entity_type entt{null};
  181. while(length--) {
  182. if(archive(entt); entt != null) {
  183. const auto entity = other.contains(entt) ? entt : other.emplace(entt);
  184. ENTT_ASSERT(entity == entt, "Entity not available for use");
  185. if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
  186. storage.emplace(entity);
  187. } else {
  188. Type elem{};
  189. archive(elem);
  190. storage.emplace(entity, std::move(elem));
  191. }
  192. }
  193. }
  194. }
  195. return *this;
  196. }
  197. /**
  198. * @brief Destroys those entities that have no components.
  199. *
  200. * In case all the entities were serialized but only part of the components
  201. * was saved, it could happen that some of the entities have no components
  202. * once restored.<br/>
  203. * This function helps to identify and destroy those entities.
  204. *
  205. * @return A valid loader to continue restoring data.
  206. */
  207. basic_snapshot_loader &orphans() {
  208. internal::orphans(*reg);
  209. return *this;
  210. }
  211. private:
  212. registry_type *reg;
  213. };
  214. /**
  215. * @brief Utility class for _continuous loading_.
  216. *
  217. * A _continuous loader_ is designed to load data from a source registry to a
  218. * (possibly) non-empty destination. The loader can accommodate in a registry
  219. * more than one snapshot in a sort of _continuous loading_ that updates the
  220. * destination one step at a time.<br/>
  221. * Identifiers that entities originally had are not transferred to the target.
  222. * Instead, the loader maps remote identifiers to local ones while restoring a
  223. * snapshot.<br/>
  224. * An example of use is the implementation of a client-server application with
  225. * the requirement of transferring somehow parts of the representation side to
  226. * side.
  227. *
  228. * @tparam Registry Basic registry type.
  229. */
  230. template<typename Registry>
  231. class basic_continuous_loader {
  232. static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
  233. using traits_type = typename Registry::traits_type;
  234. void restore(typename Registry::entity_type entt) {
  235. if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
  236. if(!reg->valid(remloc[entity].second)) {
  237. remloc[entity].second = reg->create();
  238. }
  239. } else {
  240. remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
  241. }
  242. }
  243. template<typename Container>
  244. auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
  245. // map like container
  246. Container other;
  247. for(auto &&pair: container) {
  248. using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
  249. using second_type = typename std::decay_t<decltype(pair)>::second_type;
  250. if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
  251. other.emplace(map(pair.first), map(pair.second));
  252. } else if constexpr(std::is_same_v<first_type, entity_type>) {
  253. other.emplace(map(pair.first), std::move(pair.second));
  254. } else {
  255. static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
  256. other.emplace(std::move(pair.first), map(pair.second));
  257. }
  258. }
  259. using std::swap;
  260. swap(container, other);
  261. }
  262. template<typename Container>
  263. auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
  264. // vector like container
  265. static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
  266. for(auto &&entt: container) {
  267. entt = map(entt);
  268. }
  269. }
  270. template<typename Component, typename Other, typename Member>
  271. void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
  272. if constexpr(!std::is_same_v<Component, Other>) {
  273. return;
  274. } else if constexpr(std::is_same_v<Member, entity_type>) {
  275. instance.*member = map(instance.*member);
  276. } else {
  277. // maybe a container? let's try...
  278. update(0, instance.*member);
  279. }
  280. }
  281. public:
  282. /*! Basic registry type. */
  283. using registry_type = Registry;
  284. /*! @brief Underlying entity identifier. */
  285. using entity_type = typename registry_type::entity_type;
  286. /**
  287. * @brief Constructs an instance that is bound to a given registry.
  288. * @param source A valid reference to a registry.
  289. */
  290. basic_continuous_loader(registry_type &source) noexcept
  291. : remloc{source.get_allocator()},
  292. reg{&source} {}
  293. /*! @brief Default move constructor. */
  294. basic_continuous_loader(basic_continuous_loader &&) = default;
  295. /*! @brief Default move assignment operator. @return This loader. */
  296. basic_continuous_loader &operator=(basic_continuous_loader &&) = default;
  297. /**
  298. * @brief Restores all elements of a type with associated identifiers.
  299. *
  300. * It creates local counterparts for remote elements as needed.<br/>
  301. * Members are either data members of type entity_type or containers of
  302. * entities. In both cases, a loader visits them and replaces entities with
  303. * their local counterpart.
  304. *
  305. * @tparam Type Type of elements to restore.
  306. * @tparam Archive Type of input archive.
  307. * @param archive A valid reference to an input archive.
  308. * @param id Optional name used to map the storage within the registry.
  309. * @return A valid loader to continue restoring data.
  310. */
  311. template<typename Type, typename Archive>
  312. basic_continuous_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
  313. auto &storage = reg->template storage<Type>(id);
  314. typename traits_type::entity_type length{};
  315. entity_type entt{null};
  316. archive(length);
  317. if constexpr(std::is_same_v<Type, entity_type>) {
  318. typename traits_type::entity_type in_use{};
  319. storage.reserve(length);
  320. archive(in_use);
  321. for(std::size_t pos{}; pos < in_use; ++pos) {
  322. archive(entt);
  323. restore(entt);
  324. }
  325. for(std::size_t pos = in_use; pos < length; ++pos) {
  326. archive(entt);
  327. if(const auto entity = to_entity(entt); remloc.contains(entity)) {
  328. if(reg->valid(remloc[entity].second)) {
  329. reg->destroy(remloc[entity].second);
  330. }
  331. remloc.erase(entity);
  332. }
  333. }
  334. } else {
  335. for(auto &&ref: remloc) {
  336. storage.remove(ref.second.second);
  337. }
  338. while(length--) {
  339. if(archive(entt); entt != null) {
  340. restore(entt);
  341. if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
  342. storage.emplace(map(entt));
  343. } else {
  344. Type elem{};
  345. archive(elem);
  346. storage.emplace(map(entt), std::move(elem));
  347. }
  348. }
  349. }
  350. }
  351. return *this;
  352. }
  353. /**
  354. * @brief Destroys those entities that have no components.
  355. *
  356. * In case all the entities were serialized but only part of the components
  357. * was saved, it could happen that some of the entities have no components
  358. * once restored.<br/>
  359. * This function helps to identify and destroy those entities.
  360. *
  361. * @return A non-const reference to this loader.
  362. */
  363. basic_continuous_loader &orphans() {
  364. internal::orphans(*reg);
  365. return *this;
  366. }
  367. /**
  368. * @brief Tests if a loader knows about a given entity.
  369. * @param entt A valid identifier.
  370. * @return True if `entity` is managed by the loader, false otherwise.
  371. */
  372. [[nodiscard]] bool contains(entity_type entt) const noexcept {
  373. const auto it = remloc.find(to_entity(entt));
  374. return it != remloc.cend() && it->second.first == entt;
  375. }
  376. /**
  377. * @brief Returns the identifier to which an entity refers.
  378. * @param entt A valid identifier.
  379. * @return The local identifier if any, the null entity otherwise.
  380. */
  381. [[nodiscard]] entity_type map(entity_type entt) const noexcept {
  382. if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) {
  383. return it->second.second;
  384. }
  385. return null;
  386. }
  387. private:
  388. dense_map<typename traits_type::entity_type, std::pair<entity_type, entity_type>> remloc;
  389. registry_type *reg;
  390. };
  391. } // namespace entt
  392. #endif