snapshot: registry friendship is no longer required
This commit is contained in:
9
TODO
9
TODO
@@ -16,12 +16,11 @@ Next:
|
||||
* make it easier to hook into the type system and describe how to do that to eg auto-generate meta types on first use
|
||||
* review multi component views to reduce instantiations once empty types are gone...
|
||||
* add observer functions aside observer class
|
||||
* registry clear can use the range-destroy and run much, much faster!
|
||||
|
||||
* WIP:
|
||||
- introduce the component iterators for non-contiguous collections of entities (multi component views, observers, user defined collections)
|
||||
- deprecate snapshot, loader, ...
|
||||
- provide documentation to describe alternatives
|
||||
|
||||
* WIP: snapshot rework/deprecation
|
||||
- remove snapshot/loader from registry, make them external (faster) tools
|
||||
- deprecate snapshot classes, update documentation to describe alternatives
|
||||
* WIP: snapshot rework
|
||||
- snapshot: use entity injection to load all entities at once
|
||||
- update documentation to describe alternatives
|
||||
|
||||
@@ -1580,20 +1580,9 @@ public:
|
||||
*
|
||||
* @return A temporary object to use to take snasphosts.
|
||||
*/
|
||||
[[deprecated("basic_snapshot has now a constructor that accepts a reference to a registry")]]
|
||||
entt::basic_snapshot<Entity> snapshot() const {
|
||||
using follow_fn_type = entity_type(const basic_registry &, const entity_type);
|
||||
|
||||
const auto head = to_integral(destroyed);
|
||||
const entity_type seed = (destroyed == null) ? destroyed : entity_type{head | (to_integral(entities[head]) & (traits_type::version_mask << traits_type::entity_shift))};
|
||||
|
||||
follow_fn_type *follow = [](const basic_registry ®, const entity_type entity) -> entity_type {
|
||||
const auto &others = reg.entities;
|
||||
const auto entt = to_integral(entity) & traits_type::entity_mask;
|
||||
const auto curr = to_integral(others[entt]) & traits_type::entity_mask;
|
||||
return entity_type{curr | (to_integral(others[curr]) & (traits_type::version_mask << traits_type::entity_shift))};
|
||||
};
|
||||
|
||||
return { this, seed, follow };
|
||||
return { *this };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1611,33 +1600,9 @@ public:
|
||||
*
|
||||
* @return A temporary object to use to load snasphosts.
|
||||
*/
|
||||
[[deprecated("basic_snapshot_loader has now a constructor that accepts a reference to a registry")]]
|
||||
basic_snapshot_loader<Entity> loader() {
|
||||
using force_fn_type = void(basic_registry &, const entity_type, const bool);
|
||||
|
||||
force_fn_type *force = [](basic_registry ®, const entity_type entity, const bool drop) {
|
||||
const auto entt = to_integral(entity) & traits_type::entity_mask;
|
||||
auto &others = reg.entities;
|
||||
|
||||
if(!(entt < others.size())) {
|
||||
auto curr = others.size();
|
||||
others.resize(entt + 1);
|
||||
std::generate(others.data() + curr, others.data() + entt, [&curr]() { return entity_type(curr++); });
|
||||
}
|
||||
|
||||
others[entt] = entity;
|
||||
|
||||
if(drop) {
|
||||
reg.destroy(entity);
|
||||
const auto version = to_integral(entity) & (traits_type::version_mask << traits_type::entity_shift);
|
||||
others[entt] = entity_type{(to_integral(others[entt]) & traits_type::entity_mask) | version};
|
||||
}
|
||||
};
|
||||
|
||||
clear();
|
||||
entities.clear();
|
||||
destroyed = null;
|
||||
|
||||
return { this, force };
|
||||
return { *this };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
@@ -31,15 +32,8 @@ class basic_snapshot {
|
||||
/*! @brief A registry is allowed to create snapshots. */
|
||||
friend class basic_registry<Entity>;
|
||||
|
||||
using follow_fn_type = Entity(const basic_registry<Entity> &, const Entity);
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
|
||||
basic_snapshot(const basic_registry<Entity> *source, Entity init, follow_fn_type *fn) ENTT_NOEXCEPT
|
||||
: reg{source},
|
||||
seed{init},
|
||||
follow{fn}
|
||||
{}
|
||||
|
||||
template<typename Component, typename Archive, typename It>
|
||||
void get(Archive &archive, std::size_t sz, It first, It last) const {
|
||||
archive(typename traits_type::entity_type(sz));
|
||||
@@ -71,6 +65,17 @@ class basic_snapshot {
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_snapshot(const basic_registry<entity_type> &source) ENTT_NOEXCEPT
|
||||
: reg{&source}
|
||||
{}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_snapshot(basic_snapshot &&) = default;
|
||||
|
||||
@@ -78,10 +83,10 @@ public:
|
||||
basic_snapshot & operator=(basic_snapshot &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Puts aside all the entities that are still in use.
|
||||
* @brief Puts aside all the entities from the underlying registry.
|
||||
*
|
||||
* Entities are serialized along with their versions. Destroyed entities are
|
||||
* not taken in consideration by this function.
|
||||
* taken in consideration as well by this function.
|
||||
*
|
||||
* @tparam Archive Type of output archive.
|
||||
* @param archive A valid reference to an output archive.
|
||||
@@ -89,39 +94,28 @@ public:
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot & entities(Archive &archive) const {
|
||||
archive(typename traits_type::entity_type(reg->alive()));
|
||||
reg->each([&archive](const auto entt) { archive(entt); });
|
||||
return *this;
|
||||
}
|
||||
const auto sz = reg->size();
|
||||
auto first = reg->data();
|
||||
const auto last = first + sz;
|
||||
|
||||
/**
|
||||
* @brief Puts aside destroyed entities.
|
||||
*
|
||||
* Entities are serialized along with their versions. Entities that are
|
||||
* still in use are not taken in consideration by this function.
|
||||
*
|
||||
* @tparam Archive Type of output archive.
|
||||
* @param archive A valid reference to an output archive.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot & destroyed(Archive &archive) const {
|
||||
auto size = reg->size() - reg->alive();
|
||||
archive(typename traits_type::entity_type(size));
|
||||
archive(typename traits_type::entity_type(sz));
|
||||
|
||||
if(size) {
|
||||
auto curr = seed;
|
||||
archive(curr);
|
||||
|
||||
for(--size; size; --size) {
|
||||
curr = follow(*reg, curr);
|
||||
archive(curr);
|
||||
}
|
||||
while(first != last) {
|
||||
archive(*(first++));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deprecated function. Currently, it does nothing.
|
||||
* @tparam Archive Type of output archive.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename Archive>
|
||||
[[deprecated("use ::entities instead, it exports now also destroyed entities")]]
|
||||
const basic_snapshot & destroyed(Archive &) const { return *this; }
|
||||
|
||||
/**
|
||||
* @brief Puts aside the given components.
|
||||
*
|
||||
@@ -160,9 +154,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
const basic_registry<Entity> *reg;
|
||||
const Entity seed;
|
||||
follow_fn_type *follow;
|
||||
const basic_registry<entity_type> *reg;
|
||||
};
|
||||
|
||||
|
||||
@@ -181,36 +173,15 @@ class basic_snapshot_loader {
|
||||
/*! @brief A registry is allowed to create snapshot loaders. */
|
||||
friend class basic_registry<Entity>;
|
||||
|
||||
using force_fn_type = void(basic_registry<Entity> &, const Entity, const bool);
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
|
||||
basic_snapshot_loader(basic_registry<Entity> *source, force_fn_type *fn) ENTT_NOEXCEPT
|
||||
: reg{source},
|
||||
force{fn}
|
||||
{
|
||||
// to restore a snapshot as a whole requires a clean registry
|
||||
ENTT_ASSERT(reg->empty());
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
void assure(Archive &archive, bool discard) const {
|
||||
typename traits_type::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
Entity entt{};
|
||||
archive(entt);
|
||||
force(*reg, entt, discard);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, typename Archive, typename... Args>
|
||||
void assign(Archive &archive, Args... args) const {
|
||||
typename traits_type::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
Entity entt{};
|
||||
entity_type entt{};
|
||||
|
||||
if constexpr(std::is_empty_v<Type>) {
|
||||
archive(entt);
|
||||
@@ -228,6 +199,20 @@ class basic_snapshot_loader {
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_snapshot_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
|
||||
: reg{&source}
|
||||
{
|
||||
// restoring a snapshot as a whole requires a clean registry
|
||||
ENTT_ASSERT(reg->empty());
|
||||
}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_snapshot_loader(basic_snapshot_loader &&) = default;
|
||||
|
||||
@@ -246,27 +231,28 @@ public:
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot_loader & entities(Archive &archive) const {
|
||||
static constexpr auto discard = false;
|
||||
assure(archive, discard);
|
||||
typename traits_type::entity_type length{};
|
||||
|
||||
archive(length);
|
||||
std::vector<entity_type> entities(length);
|
||||
|
||||
for(decltype(length) pos{}; pos < length; ++pos) {
|
||||
archive(entities[pos]);
|
||||
}
|
||||
|
||||
reg->assign(entities.cbegin(), entities.cend());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were destroyed during serialization.
|
||||
*
|
||||
* This function restores the entities that were destroyed during
|
||||
* serialization and gives them the versions they originally had.
|
||||
*
|
||||
* @brief Deprecated function. Currently, it does nothing.
|
||||
* @tparam Archive Type of input archive.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot_loader & destroyed(Archive &archive) const {
|
||||
static constexpr auto discard = true;
|
||||
assure(archive, discard);
|
||||
return *this;
|
||||
}
|
||||
[[deprecated("use ::entities instead, it imports now also destroyed entities")]]
|
||||
const basic_snapshot_loader & destroyed(Archive &) const { return *this; }
|
||||
|
||||
/**
|
||||
* @brief Restores components and assigns them to the right entities.
|
||||
@@ -306,8 +292,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
basic_registry<Entity> *reg;
|
||||
force_fn_type *force;
|
||||
basic_registry<entity_type> *reg;
|
||||
};
|
||||
|
||||
|
||||
@@ -364,12 +349,12 @@ class basic_continuous_loader {
|
||||
using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
|
||||
using second_type = typename std::decay_t<decltype(pair)>::second_type;
|
||||
|
||||
if constexpr(std::is_same_v<first_type, Entity> && std::is_same_v<second_type, Entity>) {
|
||||
if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
|
||||
other.emplace(map(pair.first), map(pair.second));
|
||||
} else if constexpr(std::is_same_v<first_type, Entity>) {
|
||||
} else if constexpr(std::is_same_v<first_type, entity_type>) {
|
||||
other.emplace(map(pair.first), std::move(pair.second));
|
||||
} else {
|
||||
static_assert(std::is_same_v<second_type, Entity>);
|
||||
static_assert(std::is_same_v<second_type, entity_type>);
|
||||
other.emplace(std::move(pair.first), map(pair.second));
|
||||
}
|
||||
}
|
||||
@@ -381,7 +366,7 @@ class basic_continuous_loader {
|
||||
auto update(char, Container &container)
|
||||
-> decltype(typename Container::value_type{}, void()) {
|
||||
// vector like container
|
||||
static_assert(std::is_same_v<typename Container::value_type, Entity>);
|
||||
static_assert(std::is_same_v<typename Container::value_type, entity_type>);
|
||||
|
||||
for(auto &&entt: container) {
|
||||
entt = map(entt);
|
||||
@@ -392,7 +377,7 @@ class basic_continuous_loader {
|
||||
void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type:: *member) {
|
||||
if constexpr(!std::is_same_v<Other, Type>) {
|
||||
return;
|
||||
} else if constexpr(std::is_same_v<Member, Entity>) {
|
||||
} else if constexpr(std::is_same_v<Member, entity_type>) {
|
||||
instance.*member = map(instance.*member);
|
||||
} else {
|
||||
// maybe a container? let's try...
|
||||
@@ -400,18 +385,6 @@ class basic_continuous_loader {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
void assure(Archive &archive, void(basic_continuous_loader:: *member)(Entity)) {
|
||||
typename traits_type::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
Entity entt{};
|
||||
archive(entt);
|
||||
(this->*member)(entt);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
void remove_if_exists() {
|
||||
for(auto &&ref: remloc) {
|
||||
@@ -429,7 +402,7 @@ class basic_continuous_loader {
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
Entity entt{};
|
||||
entity_type entt{};
|
||||
|
||||
if constexpr(std::is_empty_v<Other>) {
|
||||
archive(entt);
|
||||
@@ -450,7 +423,7 @@ public:
|
||||
using entity_type = Entity;
|
||||
|
||||
/**
|
||||
* @brief Constructs a loader that is bound to a given registry.
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_continuous_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
|
||||
@@ -475,25 +448,32 @@ public:
|
||||
*/
|
||||
template<typename Archive>
|
||||
basic_continuous_loader & entities(Archive &archive) {
|
||||
assure(archive, &basic_continuous_loader::restore);
|
||||
typename traits_type::entity_type length{};
|
||||
entity_type entt{};
|
||||
|
||||
archive(length);
|
||||
|
||||
for(decltype(length) pos{}; pos < length; ++pos) {
|
||||
archive(entt);
|
||||
|
||||
if(const auto entity = (to_integral(entt) & traits_type::entity_mask); entity == pos) {
|
||||
restore(entt);
|
||||
} else {
|
||||
destroy(entt);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were destroyed during serialization.
|
||||
*
|
||||
* This function restores the entities that were destroyed during
|
||||
* serialization and creates local counterparts for them if required.
|
||||
*
|
||||
* @brief Deprecated function. Currently, it does nothing.
|
||||
* @tparam Archive Type of input archive.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename Archive>
|
||||
basic_continuous_loader & destroyed(Archive &archive) {
|
||||
assure(archive, &basic_continuous_loader::destroy);
|
||||
return *this;
|
||||
}
|
||||
[[deprecated("use ::entities instead, it imports now also destroyed entities")]]
|
||||
basic_continuous_loader & destroyed(Archive &) { return *this; }
|
||||
|
||||
/**
|
||||
* @brief Restores components and assigns them to the right entities.
|
||||
|
||||
Reference in New Issue
Block a user