🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

561 lines
19 KiB

  1. #ifndef ENTT_ENTITY_SNAPSHOT_HPP
  2. #define ENTT_ENTITY_SNAPSHOT_HPP
  3. #include <array>
  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 "component.hpp"
  14. #include "entity.hpp"
  15. #include "fwd.hpp"
  16. #include "registry.hpp"
  17. namespace entt {
  18. /**
  19. * @brief Utility class to create snapshots from a registry.
  20. *
  21. * A _snapshot_ can be either a dump of the entire registry or a narrower
  22. * selection of components of interest.<br/>
  23. * This type can be used in both cases if provided with a correctly configured
  24. * output archive.
  25. *
  26. * @tparam Entity A valid entity type (see entt_traits for more details).
  27. */
  28. template<typename Entity>
  29. class basic_snapshot {
  30. using entity_traits = entt_traits<Entity>;
  31. template<typename Component, typename Archive, typename It>
  32. void get(Archive &archive, std::size_t sz, It first, It last) const {
  33. const auto view = reg->template view<std::add_const_t<Component>>();
  34. archive(typename entity_traits::entity_type(sz));
  35. while(first != last) {
  36. const auto entt = *(first++);
  37. if(reg->template all_of<Component>(entt)) {
  38. std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt)));
  39. }
  40. }
  41. }
  42. template<typename... Component, typename Archive, typename It, std::size_t... Index>
  43. void component(Archive &archive, It first, It last, std::index_sequence<Index...>) const {
  44. std::array<std::size_t, sizeof...(Index)> size{};
  45. auto begin = first;
  46. while(begin != last) {
  47. const auto entt = *(begin++);
  48. ((reg->template all_of<Component>(entt) ? ++size[Index] : 0u), ...);
  49. }
  50. (get<Component>(archive, size[Index], first, last), ...);
  51. }
  52. public:
  53. /*! @brief Underlying entity identifier. */
  54. using entity_type = Entity;
  55. /**
  56. * @brief Constructs an instance that is bound to a given registry.
  57. * @param source A valid reference to a registry.
  58. */
  59. basic_snapshot(const basic_registry<entity_type> &source) ENTT_NOEXCEPT
  60. : reg{&source} {}
  61. /*! @brief Default move constructor. */
  62. basic_snapshot(basic_snapshot &&) ENTT_NOEXCEPT = default;
  63. /*! @brief Default move assignment operator. @return This snapshot. */
  64. basic_snapshot &operator=(basic_snapshot &&) ENTT_NOEXCEPT = default;
  65. /**
  66. * @brief Puts aside all the entities from the underlying registry.
  67. *
  68. * Entities are serialized along with their versions. Destroyed entities are
  69. * taken in consideration as well by this function.
  70. *
  71. * @tparam Archive Type of output archive.
  72. * @param archive A valid reference to an output archive.
  73. * @return An object of this type to continue creating the snapshot.
  74. */
  75. template<typename Archive>
  76. const basic_snapshot &entities(Archive &archive) const {
  77. const auto sz = reg->size();
  78. archive(typename entity_traits::entity_type(sz + 1u));
  79. archive(reg->released());
  80. for(auto first = reg->data(), last = first + sz; first != last; ++first) {
  81. archive(*first);
  82. }
  83. return *this;
  84. }
  85. /**
  86. * @brief Puts aside the given components.
  87. *
  88. * Each instance is serialized together with the entity to which it belongs.
  89. * Entities are serialized along with their versions.
  90. *
  91. * @tparam Component Types of components to serialize.
  92. * @tparam Archive Type of output archive.
  93. * @param archive A valid reference to an output archive.
  94. * @return An object of this type to continue creating the snapshot.
  95. */
  96. template<typename... Component, typename Archive>
  97. const basic_snapshot &component(Archive &archive) const {
  98. if constexpr(sizeof...(Component) == 1u) {
  99. const auto view = reg->template view<const Component...>();
  100. (component<Component>(archive, view.rbegin(), view.rend()), ...);
  101. return *this;
  102. } else {
  103. (component<Component>(archive), ...);
  104. return *this;
  105. }
  106. }
  107. /**
  108. * @brief Puts aside the given components for the entities in a range.
  109. *
  110. * Each instance is serialized together with the entity to which it belongs.
  111. * Entities are serialized along with their versions.
  112. *
  113. * @tparam Component Types of components to serialize.
  114. * @tparam Archive Type of output archive.
  115. * @tparam It Type of input iterator.
  116. * @param archive A valid reference to an output archive.
  117. * @param first An iterator to the first element of the range to serialize.
  118. * @param last An iterator past the last element of the range to serialize.
  119. * @return An object of this type to continue creating the snapshot.
  120. */
  121. template<typename... Component, typename Archive, typename It>
  122. const basic_snapshot &component(Archive &archive, It first, It last) const {
  123. component<Component...>(archive, first, last, std::index_sequence_for<Component...>{});
  124. return *this;
  125. }
  126. private:
  127. const basic_registry<entity_type> *reg;
  128. };
  129. /**
  130. * @brief Utility class to restore a snapshot as a whole.
  131. *
  132. * A snapshot loader requires that the destination registry be empty and loads
  133. * all the data at once while keeping intact the identifiers that the entities
  134. * originally had.<br/>
  135. * An example of use is the implementation of a save/restore utility.
  136. *
  137. * @tparam Entity A valid entity type (see entt_traits for more details).
  138. */
  139. template<typename Entity>
  140. class basic_snapshot_loader {
  141. using entity_traits = entt_traits<Entity>;
  142. template<typename Type, typename Archive>
  143. void assign(Archive &archive) const {
  144. typename entity_traits::entity_type length{};
  145. entity_type entt;
  146. archive(length);
  147. if constexpr(ignore_as_empty_v<Type>) {
  148. while(length--) {
  149. archive(entt);
  150. const auto entity = reg->valid(entt) ? entt : reg->create(entt);
  151. ENTT_ASSERT(entity == entt, "Entity not available for use");
  152. reg->template emplace<Type>(entt);
  153. }
  154. } else {
  155. Type instance;
  156. while(length--) {
  157. archive(entt, instance);
  158. const auto entity = reg->valid(entt) ? entt : reg->create(entt);
  159. ENTT_ASSERT(entity == entt, "Entity not available for use");
  160. reg->template emplace<Type>(entt, std::move(instance));
  161. }
  162. }
  163. }
  164. public:
  165. /*! @brief Underlying entity identifier. */
  166. using entity_type = Entity;
  167. /**
  168. * @brief Constructs an instance that is bound to a given registry.
  169. * @param source A valid reference to a registry.
  170. */
  171. basic_snapshot_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
  172. : reg{&source} {
  173. // restoring a snapshot as a whole requires a clean registry
  174. ENTT_ASSERT(reg->empty(), "Registry must be empty");
  175. }
  176. /*! @brief Default move constructor. */
  177. basic_snapshot_loader(basic_snapshot_loader &&) ENTT_NOEXCEPT = default;
  178. /*! @brief Default move assignment operator. @return This loader. */
  179. basic_snapshot_loader &operator=(basic_snapshot_loader &&) ENTT_NOEXCEPT = default;
  180. /**
  181. * @brief Restores entities that were in use during serialization.
  182. *
  183. * This function restores the entities that were in use during serialization
  184. * and gives them the versions they originally had.
  185. *
  186. * @tparam Archive Type of input archive.
  187. * @param archive A valid reference to an input archive.
  188. * @return A valid loader to continue restoring data.
  189. */
  190. template<typename Archive>
  191. const basic_snapshot_loader &entities(Archive &archive) const {
  192. typename entity_traits::entity_type length{};
  193. archive(length);
  194. std::vector<entity_type> all(length);
  195. for(std::size_t pos{}; pos < length; ++pos) {
  196. archive(all[pos]);
  197. }
  198. reg->assign(++all.cbegin(), all.cend(), all[0u]);
  199. return *this;
  200. }
  201. /**
  202. * @brief Restores components and assigns them to the right entities.
  203. *
  204. * The template parameter list must be exactly the same used during
  205. * serialization. In the event that the entity to which the component is
  206. * assigned doesn't exist yet, the loader will take care to create it with
  207. * the version it originally had.
  208. *
  209. * @tparam Component Types of components to restore.
  210. * @tparam Archive Type of input archive.
  211. * @param archive A valid reference to an input archive.
  212. * @return A valid loader to continue restoring data.
  213. */
  214. template<typename... Component, typename Archive>
  215. const basic_snapshot_loader &component(Archive &archive) const {
  216. (assign<Component>(archive), ...);
  217. return *this;
  218. }
  219. /**
  220. * @brief Destroys those entities that have no components.
  221. *
  222. * In case all the entities were serialized but only part of the components
  223. * was saved, it could happen that some of the entities have no components
  224. * once restored.<br/>
  225. * This functions helps to identify and destroy those entities.
  226. *
  227. * @return A valid loader to continue restoring data.
  228. */
  229. const basic_snapshot_loader &orphans() const {
  230. reg->each([this](const auto entt) {
  231. if(reg->orphan(entt)) {
  232. reg->release(entt);
  233. }
  234. });
  235. return *this;
  236. }
  237. private:
  238. basic_registry<entity_type> *reg;
  239. };
  240. /**
  241. * @brief Utility class for _continuous loading_.
  242. *
  243. * A _continuous loader_ is designed to load data from a source registry to a
  244. * (possibly) non-empty destination. The loader can accommodate in a registry
  245. * more than one snapshot in a sort of _continuous loading_ that updates the
  246. * destination one step at a time.<br/>
  247. * Identifiers that entities originally had are not transferred to the target.
  248. * Instead, the loader maps remote identifiers to local ones while restoring a
  249. * snapshot.<br/>
  250. * An example of use is the implementation of a client-server applications with
  251. * the requirement of transferring somehow parts of the representation side to
  252. * side.
  253. *
  254. * @tparam Entity A valid entity type (see entt_traits for more details).
  255. */
  256. template<typename Entity>
  257. class basic_continuous_loader {
  258. using entity_traits = entt_traits<Entity>;
  259. void destroy(Entity entt) {
  260. if(const auto it = remloc.find(entt); it == remloc.cend()) {
  261. const auto local = reg->create();
  262. remloc.emplace(entt, std::make_pair(local, true));
  263. reg->destroy(local);
  264. }
  265. }
  266. void restore(Entity entt) {
  267. const auto it = remloc.find(entt);
  268. if(it == remloc.cend()) {
  269. const auto local = reg->create();
  270. remloc.emplace(entt, std::make_pair(local, true));
  271. } else {
  272. if(!reg->valid(remloc[entt].first)) {
  273. remloc[entt].first = reg->create();
  274. }
  275. // set the dirty flag
  276. remloc[entt].second = true;
  277. }
  278. }
  279. template<typename Container>
  280. auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
  281. // map like container
  282. Container other;
  283. for(auto &&pair: container) {
  284. using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
  285. using second_type = typename std::decay_t<decltype(pair)>::second_type;
  286. if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
  287. other.emplace(map(pair.first), map(pair.second));
  288. } else if constexpr(std::is_same_v<first_type, entity_type>) {
  289. other.emplace(map(pair.first), std::move(pair.second));
  290. } else {
  291. static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
  292. other.emplace(std::move(pair.first), map(pair.second));
  293. }
  294. }
  295. using std::swap;
  296. swap(container, other);
  297. }
  298. template<typename Container>
  299. auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
  300. // vector like container
  301. static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
  302. for(auto &&entt: container) {
  303. entt = map(entt);
  304. }
  305. }
  306. template<typename Other, typename Type, typename Member>
  307. void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type::*member) {
  308. if constexpr(!std::is_same_v<Other, Type>) {
  309. return;
  310. } else if constexpr(std::is_same_v<Member, entity_type>) {
  311. instance.*member = map(instance.*member);
  312. } else {
  313. // maybe a container? let's try...
  314. update(0, instance.*member);
  315. }
  316. }
  317. template<typename Component>
  318. void remove_if_exists() {
  319. for(auto &&ref: remloc) {
  320. const auto local = ref.second.first;
  321. if(reg->valid(local)) {
  322. reg->template remove<Component>(local);
  323. }
  324. }
  325. }
  326. template<typename Other, typename Archive, typename... Type, typename... Member>
  327. void assign(Archive &archive, [[maybe_unused]] Member Type::*...member) {
  328. typename entity_traits::entity_type length{};
  329. entity_type entt;
  330. archive(length);
  331. if constexpr(ignore_as_empty_v<Other>) {
  332. while(length--) {
  333. archive(entt);
  334. restore(entt);
  335. reg->template emplace_or_replace<Other>(map(entt));
  336. }
  337. } else {
  338. Other instance;
  339. while(length--) {
  340. archive(entt, instance);
  341. (update(instance, member), ...);
  342. restore(entt);
  343. reg->template emplace_or_replace<Other>(map(entt), std::move(instance));
  344. }
  345. }
  346. }
  347. public:
  348. /*! @brief Underlying entity identifier. */
  349. using entity_type = Entity;
  350. /**
  351. * @brief Constructs an instance that is bound to a given registry.
  352. * @param source A valid reference to a registry.
  353. */
  354. basic_continuous_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
  355. : reg{&source} {}
  356. /*! @brief Default move constructor. */
  357. basic_continuous_loader(basic_continuous_loader &&) = default;
  358. /*! @brief Default move assignment operator. @return This loader. */
  359. basic_continuous_loader &operator=(basic_continuous_loader &&) = default;
  360. /**
  361. * @brief Restores entities that were in use during serialization.
  362. *
  363. * This function restores the entities that were in use during serialization
  364. * and creates local counterparts for them if required.
  365. *
  366. * @tparam Archive Type of input archive.
  367. * @param archive A valid reference to an input archive.
  368. * @return A non-const reference to this loader.
  369. */
  370. template<typename Archive>
  371. basic_continuous_loader &entities(Archive &archive) {
  372. typename entity_traits::entity_type length{};
  373. entity_type entt{};
  374. archive(length);
  375. // discards the head of the list of destroyed entities
  376. archive(entt);
  377. for(std::size_t pos{}, last = length - 1u; pos < last; ++pos) {
  378. archive(entt);
  379. if(const auto entity = entity_traits::to_entity(entt); entity == pos) {
  380. restore(entt);
  381. } else {
  382. destroy(entt);
  383. }
  384. }
  385. return *this;
  386. }
  387. /**
  388. * @brief Restores components and assigns them to the right entities.
  389. *
  390. * The template parameter list must be exactly the same used during
  391. * serialization. In the event that the entity to which the component is
  392. * assigned doesn't exist yet, the loader will take care to create a local
  393. * counterpart for it.<br/>
  394. * Members can be either data members of type entity_type or containers of
  395. * entities. In both cases, the loader will visit them and update the
  396. * entities by replacing each one with its local counterpart.
  397. *
  398. * @tparam Component Type of component to restore.
  399. * @tparam Archive Type of input archive.
  400. * @tparam Type Types of components to update with local counterparts.
  401. * @tparam Member Types of members to update with their local counterparts.
  402. * @param archive A valid reference to an input archive.
  403. * @param member Members to update with their local counterparts.
  404. * @return A non-const reference to this loader.
  405. */
  406. template<typename... Component, typename Archive, typename... Type, typename... Member>
  407. basic_continuous_loader &component(Archive &archive, Member Type::*...member) {
  408. (remove_if_exists<Component>(), ...);
  409. (assign<Component>(archive, member...), ...);
  410. return *this;
  411. }
  412. /**
  413. * @brief Helps to purge entities that no longer have a conterpart.
  414. *
  415. * Users should invoke this member function after restoring each snapshot,
  416. * unless they know exactly what they are doing.
  417. *
  418. * @return A non-const reference to this loader.
  419. */
  420. basic_continuous_loader &shrink() {
  421. auto it = remloc.begin();
  422. while(it != remloc.cend()) {
  423. const auto local = it->second.first;
  424. bool &dirty = it->second.second;
  425. if(dirty) {
  426. dirty = false;
  427. ++it;
  428. } else {
  429. if(reg->valid(local)) {
  430. reg->destroy(local);
  431. }
  432. it = remloc.erase(it);
  433. }
  434. }
  435. return *this;
  436. }
  437. /**
  438. * @brief Destroys those entities that have no components.
  439. *
  440. * In case all the entities were serialized but only part of the components
  441. * was saved, it could happen that some of the entities have no components
  442. * once restored.<br/>
  443. * This functions helps to identify and destroy those entities.
  444. *
  445. * @return A non-const reference to this loader.
  446. */
  447. basic_continuous_loader &orphans() {
  448. reg->each([this](const auto entt) {
  449. if(reg->orphan(entt)) {
  450. reg->release(entt);
  451. }
  452. });
  453. return *this;
  454. }
  455. /**
  456. * @brief Tests if a loader knows about a given entity.
  457. * @param entt A valid identifier.
  458. * @return True if `entity` is managed by the loader, false otherwise.
  459. */
  460. [[nodiscard]] bool contains(entity_type entt) const ENTT_NOEXCEPT {
  461. return (remloc.find(entt) != remloc.cend());
  462. }
  463. /**
  464. * @brief Returns the identifier to which an entity refers.
  465. * @param entt A valid identifier.
  466. * @return The local identifier if any, the null entity otherwise.
  467. */
  468. [[nodiscard]] entity_type map(entity_type entt) const ENTT_NOEXCEPT {
  469. const auto it = remloc.find(entt);
  470. entity_type other = null;
  471. if(it != remloc.cend()) {
  472. other = it->second.first;
  473. }
  474. return other;
  475. }
  476. private:
  477. dense_map<entity_type, std::pair<entity_type, bool>> remloc;
  478. basic_registry<entity_type> *reg;
  479. };
  480. } // namespace entt
  481. #endif