1 #include <map>
2 #include <tuple>
3 #include <queue>
4 #include <vector>
5 #include <type_traits>
6 #include <gtest/gtest.h>
7 #include <entt/entity/registry.hpp>
8 #include <entt/entity/snapshot.hpp>
9 #include <entt/entity/entity.hpp>
10
11 struct noncopyable_component {
noncopyable_componentnoncopyable_component12 noncopyable_component(): value{} {}
noncopyable_componentnoncopyable_component13 explicit noncopyable_component(int v): value{v} {}
14
15 noncopyable_component(const noncopyable_component &) = delete;
16 noncopyable_component(noncopyable_component &&) = default;
17
18 noncopyable_component& operator=(const noncopyable_component &) = delete;
19 noncopyable_component& operator=(noncopyable_component &&) = default;
20
21 int value;
22 };
23
24 template<typename Storage>
25 struct output_archive {
output_archiveoutput_archive26 output_archive(Storage &instance)
27 : storage{instance}
28 {}
29
30 template<typename... Value>
operator ()output_archive31 void operator()(const Value &... value) {
32 (std::get<std::queue<Value>>(storage).push(value), ...);
33 }
34
operator ()output_archive35 void operator()(const entt::entity &entity, const noncopyable_component &instance) {
36 (*this)(entity, instance.value);
37 }
38
39 private:
40 Storage &storage;
41 };
42
43 template<typename Storage>
44 struct input_archive {
input_archiveinput_archive45 input_archive(Storage &instance)
46 : storage{instance}
47 {}
48
49 template<typename... Value>
operator ()input_archive50 void operator()(Value &... value) {
51 auto assign = [this](auto &val) {
52 auto &queue = std::get<std::queue<std::decay_t<decltype(val)>>>(storage);
53 val = queue.front();
54 queue.pop();
55 };
56
57 (assign(value), ...);
58 }
59
operator ()input_archive60 void operator()(entt::entity &entity, noncopyable_component &instance) {
61 (*this)(entity, instance.value);
62 }
63
64 private:
65 Storage &storage;
66 };
67
68 struct a_component {};
69
70 struct another_component {
71 int key;
72 int value;
73 };
74
75 struct what_a_component {
76 entt::entity bar;
77 std::vector<entt::entity> quux;
78 };
79
80 struct map_component {
81 std::map<entt::entity, int> keys;
82 std::map<int, entt::entity> values;
83 std::map<entt::entity, entt::entity> both;
84 };
85
TEST(Snapshot,Dump)86 TEST(Snapshot, Dump) {
87 using traits_type = entt::entt_traits<entt::entity>;
88
89 entt::registry registry;
90
91 const auto e0 = registry.create();
92 registry.emplace<int>(e0, 42);
93 registry.emplace<char>(e0, 'c');
94 registry.emplace<double>(e0, .1);
95
96 const auto e1 = registry.create();
97
98 const auto e2 = registry.create();
99 registry.emplace<int>(e2, 3);
100
101 const auto e3 = registry.create();
102 registry.emplace<a_component>(e3);
103 registry.emplace<char>(e3, '0');
104
105 registry.destroy(e1);
106 auto v1 = registry.current(e1);
107
108 using storage_type = std::tuple<
109 std::queue<typename traits_type::entity_type>,
110 std::queue<entt::entity>,
111 std::queue<int>,
112 std::queue<char>,
113 std::queue<double>,
114 std::queue<a_component>,
115 std::queue<another_component>
116 >;
117
118 storage_type storage;
119 output_archive<storage_type> output{storage};
120 input_archive<storage_type> input{storage};
121
122 entt::snapshot{registry}.entities(output).component<int, char, double, a_component, another_component>(output);
123 registry.clear();
124
125 ASSERT_FALSE(registry.valid(e0));
126 ASSERT_FALSE(registry.valid(e1));
127 ASSERT_FALSE(registry.valid(e2));
128 ASSERT_FALSE(registry.valid(e3));
129
130 entt::snapshot_loader{registry}.entities(input).component<int, char, double, a_component, another_component>(input).orphans();
131
132 ASSERT_TRUE(registry.valid(e0));
133 ASSERT_FALSE(registry.valid(e1));
134 ASSERT_TRUE(registry.valid(e2));
135 ASSERT_TRUE(registry.valid(e3));
136
137 ASSERT_FALSE(registry.orphan(e0));
138 ASSERT_FALSE(registry.orphan(e2));
139 ASSERT_FALSE(registry.orphan(e3));
140
141 ASSERT_EQ(registry.get<int>(e0), 42);
142 ASSERT_EQ(registry.get<char>(e0), 'c');
143 ASSERT_EQ(registry.get<double>(e0), .1);
144 ASSERT_EQ(registry.current(e1), v1);
145 ASSERT_EQ(registry.get<int>(e2), 3);
146 ASSERT_EQ(registry.get<char>(e3), '0');
147 ASSERT_TRUE(registry.all_of<a_component>(e3));
148
149 ASSERT_TRUE(registry.empty<another_component>());
150 }
151
TEST(Snapshot,Partial)152 TEST(Snapshot, Partial) {
153 using traits_type = entt::entt_traits<entt::entity>;
154
155 entt::registry registry;
156
157 const auto e0 = registry.create();
158 registry.emplace<int>(e0, 42);
159 registry.emplace<char>(e0, 'c');
160 registry.emplace<double>(e0, .1);
161
162 const auto e1 = registry.create();
163
164 const auto e2 = registry.create();
165 registry.emplace<int>(e2, 3);
166
167 const auto e3 = registry.create();
168 registry.emplace<char>(e3, '0');
169
170 registry.destroy(e1);
171 auto v1 = registry.current(e1);
172
173 using storage_type = std::tuple<
174 std::queue<typename traits_type::entity_type>,
175 std::queue<entt::entity>,
176 std::queue<int>,
177 std::queue<char>,
178 std::queue<double>
179 >;
180
181 storage_type storage;
182 output_archive<storage_type> output{storage};
183 input_archive<storage_type> input{storage};
184
185 entt::snapshot{registry}.entities(output).component<char, int>(output);
186 registry.clear();
187
188 ASSERT_FALSE(registry.valid(e0));
189 ASSERT_FALSE(registry.valid(e1));
190 ASSERT_FALSE(registry.valid(e2));
191 ASSERT_FALSE(registry.valid(e3));
192
193 entt::snapshot_loader{registry}.entities(input).component<char, int>(input);
194
195 ASSERT_TRUE(registry.valid(e0));
196 ASSERT_FALSE(registry.valid(e1));
197 ASSERT_TRUE(registry.valid(e2));
198 ASSERT_TRUE(registry.valid(e3));
199
200 ASSERT_EQ(registry.get<int>(e0), 42);
201 ASSERT_EQ(registry.get<char>(e0), 'c');
202 ASSERT_FALSE(registry.all_of<double>(e0));
203 ASSERT_EQ(registry.current(e1), v1);
204 ASSERT_EQ(registry.get<int>(e2), 3);
205 ASSERT_EQ(registry.get<char>(e3), '0');
206
207 entt::snapshot{registry}.entities(output);
208 registry.clear();
209
210 ASSERT_FALSE(registry.valid(e0));
211 ASSERT_FALSE(registry.valid(e1));
212 ASSERT_FALSE(registry.valid(e2));
213 ASSERT_FALSE(registry.valid(e3));
214
215 entt::snapshot_loader{registry}.entities(input).orphans();
216
217 ASSERT_FALSE(registry.valid(e0));
218 ASSERT_FALSE(registry.valid(e1));
219 ASSERT_FALSE(registry.valid(e2));
220 ASSERT_FALSE(registry.valid(e3));
221 }
222
TEST(Snapshot,Iterator)223 TEST(Snapshot, Iterator) {
224 using traits_type = entt::entt_traits<entt::entity>;
225
226 entt::registry registry;
227
228 for(auto i = 0; i < 50; ++i) {
229 const auto entity = registry.create();
230 registry.emplace<another_component>(entity, i, i);
231 registry.emplace<noncopyable_component>(entity, i);
232
233 if(i % 2) {
234 registry.emplace<a_component>(entity);
235 }
236 }
237
238 using storage_type = std::tuple<
239 std::queue<typename traits_type::entity_type>,
240 std::queue<entt::entity>,
241 std::queue<another_component>,
242 std::queue<int>
243 >;
244
245 storage_type storage;
246 output_archive<storage_type> output{storage};
247 input_archive<storage_type> input{storage};
248
249 const auto view = registry.view<a_component>();
250 const auto size = view.size();
251
252 entt::snapshot{registry}.component<another_component, noncopyable_component>(output, view.begin(), view.end());
253 registry.clear();
254 entt::snapshot_loader{registry}.component<another_component, noncopyable_component>(input);
255
256 ASSERT_EQ(registry.view<another_component>().size(), size);
257
258 registry.view<another_component>().each([](const auto entity, const auto &) {
259 ASSERT_NE(entt::to_integral(entity) % 2u, 0u);
260 });
261 }
262
TEST(Snapshot,Continuous)263 TEST(Snapshot, Continuous) {
264 using traits_type = entt::entt_traits<entt::entity>;
265
266 entt::registry src;
267 entt::registry dst;
268
269 entt::continuous_loader loader{dst};
270
271 std::vector<entt::entity> entities;
272 entt::entity entity;
273
274 using storage_type = std::tuple<
275 std::queue<typename traits_type::entity_type>,
276 std::queue<entt::entity>,
277 std::queue<another_component>,
278 std::queue<what_a_component>,
279 std::queue<map_component>,
280 std::queue<int>,
281 std::queue<double>
282 >;
283
284 storage_type storage;
285 output_archive<storage_type> output{storage};
286 input_archive<storage_type> input{storage};
287
288 for(int i = 0; i < 10; ++i) {
289 static_cast<void>(src.create());
290 }
291
292 src.clear();
293
294 for(int i = 0; i < 5; ++i) {
295 entity = src.create();
296 entities.push_back(entity);
297
298 src.emplace<a_component>(entity);
299 src.emplace<another_component>(entity, i, i);
300 src.emplace<noncopyable_component>(entity, i);
301
302 if(i % 2) {
303 src.emplace<what_a_component>(entity, entity);
304 } else {
305 src.emplace<map_component>(entity);
306 }
307 }
308
309 src.view<what_a_component>().each([&entities](auto, auto &what_a_component) {
310 what_a_component.quux.insert(what_a_component.quux.begin(), entities.begin(), entities.end());
311 });
312
313 src.view<map_component>().each([&entities](auto, auto &map_component) {
314 for(size_t i = 0; i < entities.size(); ++i) {
315 map_component.keys.insert({entities[i], int(i)});
316 map_component.values.insert({int(i), entities[i]});
317 map_component.both.insert({entities[entities.size() - i - 1], entities[i]});
318 }
319 });
320
321 entity = dst.create();
322 dst.emplace<a_component>(entity);
323 dst.emplace<another_component>(entity, -1, -1);
324 dst.emplace<noncopyable_component>(entity, -1);
325
326 entt::snapshot{src}.entities(output).component<a_component, another_component, what_a_component, map_component, noncopyable_component>(output);
327
328 loader.entities(input)
329 .component<a_component, another_component, what_a_component, map_component, noncopyable_component>(
330 input,
331 &what_a_component::bar,
332 &what_a_component::quux,
333 &map_component::keys,
334 &map_component::values,
335 &map_component::both
336 ).orphans();
337
338 decltype(dst.size()) a_component_cnt{};
339 decltype(dst.size()) another_component_cnt{};
340 decltype(dst.size()) what_a_component_cnt{};
341 decltype(dst.size()) map_component_cnt{};
342 decltype(dst.size()) noncopyable_component_cnt{};
343
344 dst.each([&dst, &a_component_cnt](auto entt) {
345 ASSERT_TRUE(dst.all_of<a_component>(entt));
346 ++a_component_cnt;
347 });
348
349 dst.view<another_component>().each([&another_component_cnt](auto, const auto &component) {
350 ASSERT_EQ(component.value, component.key < 0 ? -1 : component.key);
351 ++another_component_cnt;
352 });
353
354 dst.view<what_a_component>().each([&dst, &what_a_component_cnt](auto entt, const auto &component) {
355 ASSERT_EQ(entt, component.bar);
356
357 for(auto child: component.quux) {
358 ASSERT_TRUE(dst.valid(child));
359 }
360
361 ++what_a_component_cnt;
362 });
363
364 dst.view<map_component>().each([&dst, &map_component_cnt](const auto &component) {
365 for(auto child: component.keys) {
366 ASSERT_TRUE(dst.valid(child.first));
367 }
368
369 for(auto child: component.values) {
370 ASSERT_TRUE(dst.valid(child.second));
371 }
372
373 for(auto child: component.both) {
374 ASSERT_TRUE(dst.valid(child.first));
375 ASSERT_TRUE(dst.valid(child.second));
376 }
377
378 ++map_component_cnt;
379 });
380
381 dst.view<noncopyable_component>().each([&dst, &noncopyable_component_cnt](auto, const auto &component) {
382 ++noncopyable_component_cnt;
383 ASSERT_EQ(component.value, static_cast<int>(dst.size<noncopyable_component>() - noncopyable_component_cnt - 1u));
384 });
385
386 src.view<another_component>().each([](auto, auto &component) {
387 component.value = 2 * component.key;
388 });
389
390 auto size = dst.size();
391
392 entt::snapshot{src}.entities(output).component<a_component, what_a_component, map_component, another_component>(output);
393
394 loader.entities(input)
395 .component<a_component, what_a_component, map_component, another_component>(
396 input,
397 &what_a_component::bar,
398 &what_a_component::quux,
399 &map_component::keys,
400 &map_component::values,
401 &map_component::both
402 ).orphans();
403
404 ASSERT_EQ(size, dst.size());
405
406 ASSERT_EQ(dst.size<a_component>(), a_component_cnt);
407 ASSERT_EQ(dst.size<another_component>(), another_component_cnt);
408 ASSERT_EQ(dst.size<what_a_component>(), what_a_component_cnt);
409 ASSERT_EQ(dst.size<map_component>(), map_component_cnt);
410 ASSERT_EQ(dst.size<noncopyable_component>(), noncopyable_component_cnt);
411
412 dst.view<another_component>().each([](auto, auto &component) {
413 ASSERT_EQ(component.value, component.key < 0 ? -1 : (2 * component.key));
414 });
415
416 entity = src.create();
417
418 src.view<what_a_component>().each([entity](auto, auto &component) {
419 component.bar = entity;
420 });
421
422 entt::snapshot{src}.entities(output).component<what_a_component, map_component, a_component, another_component>(output);
423
424 loader.entities(input)
425 .component<what_a_component, map_component, a_component, another_component>(
426 input,
427 &what_a_component::bar,
428 &what_a_component::quux,
429 &map_component::keys,
430 &map_component::values,
431 &map_component::both
432 ).orphans();
433
434 dst.view<what_a_component>().each([&loader, entity](auto, auto &component) {
435 ASSERT_EQ(component.bar, loader.map(entity));
436 });
437
438 entities.clear();
439 for(auto entt: src.view<a_component>()) {
440 entities.push_back(entt);
441 }
442
443 src.destroy(entity);
444 loader.shrink();
445
446 entt::snapshot{src}.entities(output).component<a_component, another_component, what_a_component, map_component>(output);
447
448 loader.entities(input)
449 .component<a_component, another_component, what_a_component, map_component>(
450 input,
451 &what_a_component::bar,
452 &what_a_component::quux,
453 &map_component::keys,
454 &map_component::values,
455 &map_component::both
456 ).orphans().shrink();
457
458 dst.view<what_a_component>().each([&dst](auto, auto &component) {
459 ASSERT_FALSE(dst.valid(component.bar));
460 });
461
462 ASSERT_FALSE(loader.contains(entity));
463
464 entity = src.create();
465
466 src.view<what_a_component>().each([entity](auto, auto &component) {
467 component.bar = entity;
468 });
469
470 dst.clear<a_component>();
471 a_component_cnt = src.size<a_component>();
472
473 entt::snapshot{src}.entities(output).component<a_component, what_a_component, map_component, another_component>(output);
474
475 loader.entities(input)
476 .component<a_component, what_a_component, map_component, another_component>(
477 input,
478 &what_a_component::bar,
479 &what_a_component::quux,
480 &map_component::keys,
481 &map_component::values,
482 &map_component::both
483 ).orphans();
484
485 ASSERT_EQ(dst.size<a_component>(), a_component_cnt);
486
487 src.clear<a_component>();
488 a_component_cnt = {};
489
490 entt::snapshot{src}.entities(output).component<what_a_component, map_component, a_component, another_component>(output);
491
492 loader.entities(input)
493 .component<what_a_component, map_component, a_component, another_component>(
494 input,
495 &what_a_component::bar,
496 &what_a_component::quux,
497 &map_component::keys,
498 &map_component::values,
499 &map_component::both
500 ).orphans();
501
502 ASSERT_EQ(dst.size<a_component>(), a_component_cnt);
503 }
504
TEST(Snapshot,MoreOnShrink)505 TEST(Snapshot, MoreOnShrink) {
506 using traits_type = entt::entt_traits<entt::entity>;
507
508 entt::registry src;
509 entt::registry dst;
510
511 entt::continuous_loader loader{dst};
512
513 using storage_type = std::tuple<
514 std::queue<typename traits_type::entity_type>,
515 std::queue<entt::entity>
516 >;
517
518 storage_type storage;
519 output_archive<storage_type> output{storage};
520 input_archive<storage_type> input{storage};
521
522 auto entity = src.create();
523 entt::snapshot{src}.entities(output);
524 loader.entities(input).shrink();
525
526 ASSERT_TRUE(dst.valid(entity));
527
528 loader.shrink();
529
530 ASSERT_FALSE(dst.valid(entity));
531 }
532
TEST(Snapshot,SyncDataMembers)533 TEST(Snapshot, SyncDataMembers) {
534 using traits_type = entt::entt_traits<entt::entity>;
535
536 entt::registry src;
537 entt::registry dst;
538
539 entt::continuous_loader loader{dst};
540
541 using storage_type = std::tuple<
542 std::queue<typename traits_type::entity_type>,
543 std::queue<entt::entity>,
544 std::queue<what_a_component>,
545 std::queue<map_component>
546 >;
547
548 storage_type storage;
549 output_archive<storage_type> output{storage};
550 input_archive<storage_type> input{storage};
551
552 static_cast<void>(src.create());
553 static_cast<void>(src.create());
554
555 src.clear();
556
557 auto parent = src.create();
558 auto child = src.create();
559
560
561 src.emplace<what_a_component>(parent, entt::null);
562 src.emplace<what_a_component>(child, parent).quux.push_back(child);
563
564 src.emplace<map_component>(
565 child,
566 decltype(map_component::keys){{{ child, 10 }}},
567 decltype(map_component::values){{{ 10, child }}},
568 decltype(map_component::both){{{ child, child }}}
569 );
570
571 entt::snapshot{src}.entities(output).component<what_a_component, map_component>(output);
572
573 loader.entities(input).component<what_a_component, map_component>(
574 input,
575 &what_a_component::bar,
576 &what_a_component::quux,
577 &map_component::keys,
578 &map_component::values,
579 &map_component::both
580 );
581
582 ASSERT_FALSE(dst.valid(parent));
583 ASSERT_FALSE(dst.valid(child));
584
585 ASSERT_TRUE(dst.all_of<what_a_component>(loader.map(parent)));
586 ASSERT_TRUE(dst.all_of<what_a_component>(loader.map(child)));
587
588 ASSERT_EQ(dst.get<what_a_component>(loader.map(parent)).bar, static_cast<entt::entity>(entt::null));
589
590 const auto &component = dst.get<what_a_component>(loader.map(child));
591
592 ASSERT_EQ(component.bar, loader.map(parent));
593 ASSERT_EQ(component.quux[0], loader.map(child));
594
595 const auto &foobar = dst.get<map_component>(loader.map(child));
596 ASSERT_EQ(foobar.keys.at(loader.map(child)), 10);
597 ASSERT_EQ(foobar.values.at(10), loader.map(child));
598 ASSERT_EQ(foobar.both.at(loader.map(child)), loader.map(child));
599 }
600