Snapshot loader can auto-update entities stored in maps now (#335) - close #334

* Detect if member variable is of type map and update the contained entities if needed
* issue 334: tests for identifier update on maps in snapshots
This commit is contained in:
Stephan Z
2019-10-16 21:59:54 +02:00
committed by Michele Caini
parent 1ad75f5c1b
commit 135132e5f0
3 changed files with 171 additions and 44 deletions

View File

@@ -31,6 +31,7 @@ Paolo-Oliverio
pgruenbacher
prowolf
suVrik
szunhammer
The5-1
vblanco20-1
willtunnels

View File

@@ -353,6 +353,40 @@ class basic_continuous_loader {
}
}
template<typename Container>
auto update(int, Container &container)
-> decltype(typename Container::mapped_type{}, void()) {
// map like container
Container other;
for(auto &&pair: container) {
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>) {
other.emplace(map(pair.first), map(pair.second));
} else if constexpr(std::is_same_v<first_type, Entity>) {
other.emplace(map(pair.first), std::move(pair.second));
} else {
static_assert(std::is_same_v<second_type, Entity>);
other.emplace(std::move(pair.first), map(pair.second));
}
}
std::swap(container, other);
}
template<typename Container>
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>);
for(auto &&entt: container) {
entt = map(entt);
}
}
template<typename Other, typename Type, typename Member>
void update(Other &instance, Member Type:: *member) {
if constexpr(!std::is_same_v<Other, Type>) {
@@ -361,9 +395,7 @@ class basic_continuous_loader {
instance.*member = map(instance.*member);
} else {
// maybe a container? let's try...
for(auto &entt: instance.*member) {
entt = map(entt);
}
update(0, instance.*member);
}
}

View File

@@ -1,3 +1,4 @@
#include <map>
#include <tuple>
#include <queue>
#include <vector>
@@ -54,6 +55,12 @@ struct what_a_component {
std::vector<entt::entity> quux;
};
struct map_component {
std::map<entt::entity, int> keys;
std::map<int, entt::entity> values;
std::map<entt::entity, entt::entity> both;
};
TEST(Snapshot, Dump) {
using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
@@ -266,6 +273,7 @@ TEST(Snapshot, Continuous) {
std::queue<entt::entity>,
std::queue<another_component>,
std::queue<what_a_component>,
std::queue<map_component>,
std::queue<double>
>;
@@ -288,6 +296,8 @@ TEST(Snapshot, Continuous) {
if(i % 2) {
src.assign<what_a_component>(entity, entity);
} else {
src.assign<map_component>(entity);
}
}
@@ -295,23 +305,38 @@ TEST(Snapshot, Continuous) {
what_a_component.quux.insert(what_a_component.quux.begin(), entities.begin(), entities.end());
});
src.view<map_component>().each([&entities](auto, auto &map_component) {
for(size_t i = 0; i < entities.size(); ++i) {
map_component.keys.insert({entities[i], int(i)});
map_component.values.insert({int(i), entities[i]});
map_component.both.insert({entities[entities.size() - i - 1], entities[i]});
}
});
entity = dst.create();
dst.assign<a_component>(entity);
dst.assign<another_component>(entity, -1, -1);
src.snapshot()
.entities(output)
.destroyed(output)
.component<a_component, another_component, what_a_component>(output);
.entities(output)
.destroyed(output)
.component<a_component, another_component, what_a_component, map_component>(output);
loader.entities(input)
.destroyed(input)
.component<a_component, another_component, what_a_component>(input, &what_a_component::bar, &what_a_component::quux)
.orphans();
.destroyed(input)
.component<a_component, another_component, what_a_component, map_component>(
input,
&what_a_component::bar,
&what_a_component::quux,
&map_component::keys,
&map_component::values,
&map_component::both
).orphans();
decltype(dst.size()) a_component_cnt{};
decltype(dst.size()) another_component_cnt{};
decltype(dst.size()) what_a_component_cnt{};
decltype(dst.size()) map_component_cnt{};
dst.each([&dst, &a_component_cnt](auto entt) {
ASSERT_TRUE(dst.has<a_component>(entt));
@@ -333,6 +358,23 @@ TEST(Snapshot, Continuous) {
++what_a_component_cnt;
});
dst.view<map_component>().each([&dst, &map_component_cnt](const auto &component) {
for(auto child: component.keys) {
ASSERT_TRUE(dst.valid(child.first));
}
for(auto child: component.values) {
ASSERT_TRUE(dst.valid(child.second));
}
for(auto child: component.both) {
ASSERT_TRUE(dst.valid(child.first));
ASSERT_TRUE(dst.valid(child.second));
}
++map_component_cnt;
});
src.view<another_component>().each([](auto, auto &component) {
component.value = 2 * component.key;
});
@@ -340,20 +382,27 @@ TEST(Snapshot, Continuous) {
auto size = dst.size();
src.snapshot()
.entities(output)
.destroyed(output)
.component<a_component, what_a_component, another_component>(output);
.entities(output)
.destroyed(output)
.component<a_component, what_a_component, map_component, another_component>(output);
loader.entities(input)
.destroyed(input)
.component<a_component, what_a_component, another_component>(input, &what_a_component::bar, &what_a_component::quux)
.orphans();
.destroyed(input)
.component<a_component, what_a_component, map_component, another_component>(
input,
&what_a_component::bar,
&what_a_component::quux,
&map_component::keys,
&map_component::values,
&map_component::both
).orphans();
ASSERT_EQ(size, dst.size());
ASSERT_EQ(dst.size<a_component>(), a_component_cnt);
ASSERT_EQ(dst.size<another_component>(), another_component_cnt);
ASSERT_EQ(dst.size<what_a_component>(), what_a_component_cnt);
ASSERT_EQ(dst.size<map_component>(), map_component_cnt);
dst.view<another_component>().each([](auto, auto &component) {
ASSERT_EQ(component.value, component.key < 0 ? -1 : (2 * component.key));
@@ -366,14 +415,20 @@ TEST(Snapshot, Continuous) {
});
src.snapshot()
.entities(output)
.destroyed(output)
.component<what_a_component, a_component, another_component>(output);
.entities(output)
.destroyed(output)
.component<what_a_component, map_component, a_component, another_component>(output);
loader.entities(input)
.destroyed(input)
.component<what_a_component, a_component, another_component>(input, &what_a_component::bar, &what_a_component::quux)
.orphans();
.destroyed(input)
.component<what_a_component, map_component, a_component, another_component>(
input,
&what_a_component::bar,
&what_a_component::quux,
&map_component::keys,
&map_component::values,
&map_component::both
).orphans();
dst.view<what_a_component>().each([&loader, entity](auto, auto &component) {
ASSERT_EQ(component.bar, loader.map(entity));
@@ -388,15 +443,20 @@ TEST(Snapshot, Continuous) {
loader.shrink();
src.snapshot()
.entities(output)
.destroyed(output)
.component<a_component, another_component, what_a_component>(output);
.entities(output)
.destroyed(output)
.component<a_component, another_component, what_a_component, map_component>(output);
loader.entities(input)
.destroyed(input)
.component<a_component, another_component, what_a_component>(input, &what_a_component::bar, &what_a_component::quux)
.orphans()
.shrink();
.destroyed(input)
.component<a_component, another_component, what_a_component, map_component>(
input,
&what_a_component::bar,
&what_a_component::quux,
&map_component::keys,
&map_component::values,
&map_component::both
).orphans().shrink();
dst.view<what_a_component>().each([&dst](auto, auto &component) {
ASSERT_FALSE(dst.valid(component.bar));
@@ -414,14 +474,20 @@ TEST(Snapshot, Continuous) {
a_component_cnt = src.size<a_component>();
src.snapshot()
.entities(output)
.destroyed(output)
.component<a_component, what_a_component, another_component>(output);
.entities(output)
.destroyed(output)
.component<a_component, what_a_component, map_component, another_component>(output);
loader.entities(input)
.destroyed(input)
.component<a_component, what_a_component, another_component>(input, &what_a_component::bar, &what_a_component::quux)
.orphans();
.destroyed(input)
.component<a_component, what_a_component, map_component, another_component>(
input,
&what_a_component::bar,
&what_a_component::quux,
&map_component::keys,
&map_component::values,
&map_component::both
).orphans();
ASSERT_EQ(dst.size<a_component>(), a_component_cnt);
@@ -429,14 +495,20 @@ TEST(Snapshot, Continuous) {
a_component_cnt = {};
src.snapshot()
.entities(output)
.destroyed(output)
.component<what_a_component, a_component, another_component>(output);
.entities(output)
.destroyed(output)
.component<what_a_component, map_component, a_component, another_component>(output);
loader.entities(input)
.destroyed(input)
.component<what_a_component, a_component, another_component>(input, &what_a_component::bar, &what_a_component::quux)
.orphans();
.destroyed(input)
.component<what_a_component, map_component, a_component, another_component>(
input,
&what_a_component::bar,
&what_a_component::quux,
&map_component::keys,
&map_component::values,
&map_component::both
).orphans();
ASSERT_EQ(dst.size<a_component>(), a_component_cnt);
}
@@ -452,7 +524,7 @@ TEST(Snapshot, MoreOnShrink) {
using storage_type = std::tuple<
std::queue<typename traits_type::entity_type>,
std::queue<entt::entity>
>;
>;
storage_type storage;
output_archive<storage_type> output{storage};
@@ -480,7 +552,8 @@ TEST(Snapshot, SyncDataMembers) {
using storage_type = std::tuple<
std::queue<typename traits_type::entity_type>,
std::queue<entt::entity>,
std::queue<what_a_component>
std::queue<what_a_component>,
std::queue<map_component>
>;
storage_type storage;
@@ -495,11 +568,27 @@ TEST(Snapshot, SyncDataMembers) {
auto parent = src.create();
auto child = src.create();
src.assign<what_a_component>(parent, entt::null);
src.assign<what_a_component>(child, parent).quux.push_back(child);
src.snapshot().entities(output).component<what_a_component>(output);
loader.entities(input).component<what_a_component>(input, &what_a_component::bar, &what_a_component::quux);
src.assign<map_component>(
child,
decltype(map_component::keys){{{ child, 10 }}},
decltype(map_component::values){{{ 10, child }}},
decltype(map_component::both){{{ child, child }}}
);
src.snapshot().entities(output).component<what_a_component, map_component>(output);
loader.entities(input).component<what_a_component, map_component>(
input,
&what_a_component::bar,
&what_a_component::quux,
&map_component::keys,
&map_component::values,
&map_component::both
);
ASSERT_FALSE(dst.valid(parent));
ASSERT_FALSE(dst.valid(child));
@@ -513,4 +602,9 @@ TEST(Snapshot, SyncDataMembers) {
ASSERT_EQ(component.bar, loader.map(parent));
ASSERT_EQ(component.quux[0], loader.map(child));
const auto &foobar = dst.get<map_component>(loader.map(child));
ASSERT_EQ(foobar.keys.at(loader.map(child)), 10);
ASSERT_EQ(foobar.values.at(10), loader.map(child));
ASSERT_EQ(foobar.both.at(loader.map(child)), loader.map(child));
}