Unravel Engine C++ Reference
Loading...
Searching...
No Matches
entity.cpp
Go to the documentation of this file.
1#include "entity.hpp"
2
3#include <chrono>
9#include <engine/engine.h>
10#include <engine/events.h>
14
15#include "entt/entity/fwd.hpp"
16#include "logging/logging.h"
18#include "uuid/uuid.h"
19
20#include <hpp/utility.hpp>
21#include <sstream>
22
23namespace unravel
24{
25
26auto const_handle_cast(entt::const_handle chandle) -> entt::handle
27{
28 entt::handle handle(*const_cast<entt::handle::registry_type*>(chandle.registry()), chandle.entity());
29 return handle;
30}
31
32template<typename Entity>
34{
35 Entity entity;
36};
37
38template<typename Entity>
43
44auto as_span(const std::vector<entity_data<entt::handle>>& entities) -> hpp::span<const entt::handle>
45{
46 // pointer to the first entity_data
47 auto* base = entities.data();
48
49 // compute the address of the first entt::handle
50 constexpr size_t offset = offsetof(entity_data<entt::handle>, components.entity);
51
52 auto* first_handle = reinterpret_cast<const entt::handle*>(reinterpret_cast<const std::uint8_t*>(base) + offset);
53
54 // build a span over all of them
55 hpp::span<const entt::handle> handles{first_handle, entities.size()};
56 return handles;
57}
58
59thread_local load_context* load_ctx_ptr{};
60thread_local save_context* save_ctx_ptr{};
61std::atomic_bool writing = false;
62std::atomic_bool reading = false;
63
64auto push_load_context(entt::registry& registry) -> bool
65{
66 if(load_ctx_ptr)
67 {
68 return false;
69 }
71 load_ctx_ptr->reg = &registry;
72 return true;
73}
74
75void pop_load_context(bool push_result)
76{
77 if(push_result && load_ctx_ptr)
78 {
79 delete load_ctx_ptr;
80 load_ctx_ptr = {};
81 }
82}
83
85{
86 assert(load_ctx_ptr);
87 return *load_ctx_ptr;
88}
89
90auto push_save_context() -> bool
91{
92 if(save_ctx_ptr)
93 {
94 return false;
95 }
97
98 return true;
99}
100
101void pop_save_context(bool push_result)
102{
103 if(push_result && save_ctx_ptr)
104 {
105 delete save_ctx_ptr;
106 save_ctx_ptr = {};
107 }
108}
109
110
112{
113 assert(save_ctx_ptr);
114 return *save_ctx_ptr;
115}
116void add_to_uid_mapping(entt::handle& obj, bool recursive = true)
117{
118 auto& load_ctx = get_load_context();
119
120 auto id_comp = obj.try_get<prefab_id_component>();
121 if(id_comp)
122 {
123 id_comp->generate_if_nil();
124 load_ctx.mapping_by_uid[id_comp->id].handle = obj;
125 }
126
127
128 if(auto prefab_comp = obj.try_get<prefab_component>())
129 {
130 for(auto& entity_uuid : prefab_comp->removed_entities)
131 {
132 load_ctx.mapping_by_uid[entity_uuid].handle = {};
133 }
134 }
135
136 if(recursive )
137 {
138 if(auto trans_comp = obj.try_get<transform_component>())
139 {
140 for(auto child : trans_comp->get_children())
141 {
142 add_to_uid_mapping(child, recursive);
143 }
144 }
145 }
146}
147
149{
150
151 auto& load_ctx = get_load_context();
152 for(auto& [uid, mapping] : load_ctx.mapping_by_uid)
153 {
154 if(!mapping.consumed && mapping.handle)
155 {
156 // APPLOG_TRACE("destroying entity: {}", uid.to_string());
157 mapping.handle.destroy();
158 }
159 }
160}
161
162
163auto is_parent(entt::const_handle potential_parent, entt::const_handle child) -> bool
164{
165 if(!potential_parent)
166 {
167 return false;
168 }
169 // Traverse up the hierarchy from `child`
170 while(true)
171 {
172 // Access the transform component once per entity
173 const auto* transform = child.try_get<transform_component>();
174 if(!transform)
175 {
176 return false; // Reached the root without finding `potential_parent`
177 }
178 auto parent = transform->get_parent();
179 if(!parent)
180 {
181 return false;
182 }
183
184 if(parent == potential_parent)
185 {
186 return true; // Found the parent relationship
187 }
188
189 child = parent; // Move up the hierarchy
190 }
191}
192auto find_root(entt::const_handle e) -> entt::const_handle
193{
194 // Loop to find the root entity
195 while(true)
196 {
197 // Access the `transform_component` once
198 const auto* transform = e.try_get<transform_component>();
199 if(!transform || !transform->get_parent())
200 {
201 break; // If no parent, we are at the root
202 }
203 e = transform->get_parent(); // Move to the parent entity
204 }
205 return e; // Root entity
206}
207
208auto are_related(entt::const_handle lhs, entt::const_handle rhs) -> bool
209{
210 return find_root(lhs) == find_root(rhs);
211}
212
219
220auto push_entity_path(entt::const_handle obj) -> bool
221{
223 if(ctx)
224 {
225 if(auto id = obj.try_get<prefab_id_component>())
226 {
227 ctx->push_segment(id->id.to_string());
228 return true;
229 }
230 }
231 return false;
232}
233
234void pop_entity_path(bool pushed)
235{
237 if(pushed && ctx)
238 {
239 ctx->pop_segment();
240 }
241}
242
243} // namespace unravel
244
245using namespace unravel;
246
247namespace ser20
248{
249
250template<typename Archive>
251void save_entity_id(Archive& ar, const entt::const_handle& obj)
252{
253 entt::handle::entity_type id = obj.valid() ? obj.entity() : entt::null;
254 try_save(ar, ser20::make_nvp("id", id));
255}
256
257template<typename Archive>
258void save_entity_uid(Archive& ar, const entt::const_handle& obj)
259{
260 if(obj)
261 {
262 auto& id_comp = const_handle_cast(obj).get_or_emplace<prefab_id_component>();
263 id_comp.generate_if_nil();
264
265 try_save(ar, ser20::make_nvp("prefab_uid", id_comp.id));
266 }
267 else
268 {
269 try_save(ar, ser20::make_nvp("prefab_uid", hpp::uuid{}));
270 }
271}
272
273template<typename Archive>
274void save_entity(Archive& ar, const entt::const_handle& obj, entity_flags flags)
275{
276 auto& save_ctx = get_save_context();
277 if(save_ctx.is_saving_to_prefab())
278 {
279 save_entity_uid(ar, obj);
280 }
281
282 save_entity_id(ar, obj);
283}
284
285template<typename Archive>
286auto load_entity_from_id(Archive& ar, entt::handle& obj, entity_flags flags) -> bool
287{
288 entt::handle::entity_type id{};
289 bool valid = try_load(ar, ser20::make_nvp("id", id));
290
291 valid &= id != entt::null && id != entt::handle::entity_type(0);
292 if(valid)
293 {
294 auto& load_ctx = get_load_context();
295 auto it = load_ctx.mapping_by_eid.find(id);
296 if(it != load_ctx.mapping_by_eid.end())
297 {
298 obj = it->second;
299 // APPLOG_TRACE("found in cache entity from id: {}", uint32_t(id));
300 }
301 else if(obj)
302 {
303 load_ctx.mapping_by_eid[id] = obj;
304 // APPLOG_TRACE("added to cache entity from id: {}", uint32_t(id));
305 }
306 else
307 {
308 if(flags == entity_flags::resolve_with_existing)
309 {
310 entt::handle check_entity(*load_ctx.reg, id);
311 if(check_entity)
312 {
313 obj = check_entity;
314 load_ctx.mapping_by_eid[id] = obj;
315 // APPLOG_TRACE("added to cache entity from id: {}", uint32_t(id));
316 }
317 else
318 {
319 obj = {};
320 }
321 }
322 else
323 {
324 obj = entt::handle(*load_ctx.reg, load_ctx.reg->create());
325 load_ctx.mapping_by_eid[id] = obj;
326 // APPLOG_TRACE("created and added to cache entity from id: {}", uint32_t(id));
327 }
328 }
329 }
330
331
332 return valid;
333}
334
335template<typename Archive>
336auto load_entity_from_uid(Archive& ar, entt::handle& obj, entity_flags flags) -> bool
337{
338 hpp::uuid uid;
339 try_load(ar, ser20::make_nvp("prefab_uid", uid));
340
341
342 auto& load_ctx = get_load_context();
343 auto it = load_ctx.mapping_by_uid.find(uid);
344 if(it != load_ctx.mapping_by_uid.end())
345 {
346 // APPLOG_TRACE("found in cache entity from uid: {}", uid.to_string());
347 obj = it->second.handle;
348 it->second.consumed = true;
349 return true;
350 }
351
352 return false;
353}
354
355template<typename Archive>
356void load_entity(Archive& ar, entt::handle& obj, entity_flags flags)
357{
358 bool valid = false;
359 auto& load_ctx = get_load_context();
360 if(load_ctx.is_updating_prefab())
361 {
362 valid = load_entity_from_uid(ar, obj, flags);
363 }
364
365 if(!valid)
366 {
367 valid = load_entity_from_id(ar, obj, flags);
368 }
369
370 if(!valid)
371 {
372 obj = {};
373 }
374}
375
376template<typename Component>
377auto should_save_component(const entt::const_handle& obj) -> bool
378{
379 if constexpr(std::is_same_v<Component, prefab_component>)
380 {
381 // if we are saving to prefab, we don't want to save the prefab component
382 auto& save_ctx = get_save_context();
383
384 if(save_ctx.is_saving_to_prefab())
385 {
386 return false;
387 }
388 }
389 else if constexpr(std::is_same_v<Component, prefab_id_component>)
390 {
391 // if we are cloning
392 // we need to generate a new id for the entity
393 auto& save_ctx = get_save_context();
394 if(save_ctx.is_cloning())
395 {
396 if(save_ctx.get_clone_mode() != clone_mode_t::cloning_prefab_instance)
397 {
398 return false;
399 }
400 }
401 }
402 return true;
403}
404
405template<typename Component>
406auto should_load_component(const entt::handle& obj) -> bool
407{
408 // if constexpr(std::is_same_v<Component, prefab_component>)
409 // {
410 // return false;
411 // }
412 // else if constexpr(std::is_same_v<Component, prefab_id_component>)
413 // {
414
415 // return false;
416 // }
417
418
419 return true;
420}
421
422SAVE(entt::const_handle)
423{
424 save_entity(ar, obj, entity_flags::none);
425}
428
429LOAD(entt::handle)
430{
431
432 load_entity(ar, obj, entity_flags::none);
433}
434
437
439{
440 // Saving entity links is a little more complex than just entities
441 // The rule is as follows.
442 // If we are saving as single entity hierarch :
443 // If the entity link is not part of it :
444 // -> if we are saving to prefab, break the link
445 // -> if we are duplicating resolve the link on load with exsisting scene.
446 entity_flags flags = entity_flags::resolve_with_loaded;
447 entt::const_handle to_save = obj.handle;
448
449 auto& save_ctx = get_save_context();
450
451 bool is_saving_single = save_ctx.save_source.valid();
452 if(is_saving_single)
453 {
454 // is the entity a child of the hierarchy that we are saving?
455 bool save_source_is_parent = is_parent(save_ctx.save_source, obj.handle);
456
457 // if it is an external entity
458 if(!save_source_is_parent)
459 {
460 if(save_ctx.is_saving_to_prefab())
461 {
462 // when saving prefabs, external entities
463 // should not be saved
464 to_save = {};
465 }
466 else
467 {
468 // when saving entities for duplication purpose, external entities
469 // should not be resolved from the existing scene
470 flags = entity_flags::resolve_with_existing;
471 }
472 }
473 else
474 {
475 if(!save_ctx.is_saving_to_prefab())
476 {
477 flags = entity_flags::resolve_with_existing;
478 }
479 }
480 }
481
482 try_save(ar, ser20::make_nvp("flags", flags));
483 save_entity(ar, to_save, flags);
484}
487
489{
490 entity_flags flags{};
491 try_load(ar, ser20::make_nvp("flags", flags));
492
493 load_entity(ar, obj.handle, flags);
494}
495
498
499
500
502{
503 hpp::for_each_tuple_type<unravel::all_serializeable_components>(
504 [&](auto index)
505 {
506 using ctype = std::tuple_element_t<decltype(index)::value, unravel::all_serializeable_components>;
507
508 if(!should_save_component<ctype>(obj.entity))
509 {
510 return;
511 }
512
513 auto component = obj.entity.try_get<ctype>();
514
515 const auto type = entt::resolve<ctype>();
516 auto name = entt::get_name(type);
517
518 if(component)
519 {
520 try_save(ar, ser20::make_nvp("has_" + name, true));
521 try_save(ar, ser20::make_nvp(name, *component));
522 }
523
524 });
525}
528
530{
531 hpp::for_each_tuple_type<unravel::all_serializeable_components>(
532 [&](auto index)
533 {
534 using ctype = std::tuple_element_t<decltype(index)::value, unravel::all_serializeable_components>;
535
536 if(!should_load_component<ctype>(obj.entity))
537 {
538 return;
539 }
540
541
542 auto component_type = entt::resolve<ctype>();
543 auto name = entt::get_name(component_type);
544 auto pretty_name = entt::get_pretty_name(component_type);
545
546 auto has_name = "has_" + name;
547 auto pretty_has_name = "Has" + pretty_name;
548
549
550 bool has_component = false;
551 {
552 bool success_has_component = false;
553
554 success_has_component |= serialize_check(has_name, [&]() -> bool
555 {
556 return try_serialize_direct(ar, ser20::make_nvp(pretty_has_name, has_component));
557 });
558
559 if(!success_has_component)
560 {
561 success_has_component |= serialize_check(has_name, [&]() -> bool
562 {
563 return try_serialize_direct(ar, ser20::make_nvp(has_name, has_component));
564 });
565 }
566 }
567
568 if(has_component)
569 {
570 auto& component = obj.entity.get_or_emplace<ctype>();
571
572 bool success_component = false;
573 {
574 // Legacy support with pretty name
575 success_component |= serialize_check(name, [&]() -> bool
576 {
577 return try_serialize_direct(ar, ser20::make_nvp(pretty_name, component));
578 });
579 }
580
581 if(!success_component)
582 {
583 success_component |= serialize_check(name, [&]() -> bool
584 {
585 return try_serialize_direct(ar, ser20::make_nvp(name, component));
586 });
587 }
588 }
589
590
591 if constexpr(std::is_same_v<ctype, tag_component>)
592 {
593 auto& comp = obj.entity.get_or_emplace<ctype>();
594 (void)comp;
595 }
596 if constexpr(std::is_same_v<ctype, layer_component>)
597 {
598 auto& comp = obj.entity.get_or_emplace<ctype>();
599 (void)comp;
600 }
601
602 });
603
604
605 // if we are cloning
606 // we need to generate a new id for the entity
607 auto& load_ctx = get_load_context();
608 if(load_ctx.is_cloning())
609 {
610 if(load_ctx.get_clone_mode() != clone_mode_t::cloning_prefab_instance)
611 {
612 // and are not the root of the prefab,
613 obj.entity.remove<prefab_id_component>();
614 }
615
616 auto id_comp = obj.entity.try_get<id_component>();
617 if(id_comp)
618 {
619 id_comp->regenerate_id();
620 }
621 }
622}
625
627{
628 SAVE_FUNCTION_NAME(ar, obj.components.entity);
629 try_save(ar, ser20::make_nvp("components", obj.components));
630}
633
635{
636 entt::handle e;
637 LOAD_FUNCTION_NAME(ar, e);
638
639 if(e)
640 {
641 bool pushed = push_entity_path(e);
642 obj.components.entity = e;
643 try_load(ar, ser20::make_nvp("components", obj.components));
644 pop_entity_path(pushed);
645 }
646}
649
650} // namespace ser20
651
652namespace unravel
653{
654namespace
655{
656
657void flatten_hierarchy(entt::const_handle obj, std::vector<entity_data<entt::const_handle>>& entities)
658{
659 auto& trans_comp = obj.get<transform_component>();
660 const auto& children = trans_comp.get_children();
661
663 data.components.entity = obj;
664
665 entities.emplace_back(data);
666
667 entities.reserve(entities.size() + children.size());
668 for(const auto& child : children)
669 {
670 flatten_hierarchy(child, entities);
671 }
672}
673
674template<typename Archive>
675void save_to_archive(Archive& ar, entt::const_handle obj)
676{
677 bool pushed = push_save_context();
678
679 bool is_root = obj.all_of<root_component>();
680 if(!is_root)
681 {
682 const_handle_cast(obj).emplace<root_component>();
683 }
684
685 auto& trans_comp = obj.get<transform_component>();
686
687 std::vector<entity_data<entt::const_handle>> entities;
688 flatten_hierarchy(obj, entities);
689
690 try_save(ar, ser20::make_nvp("entities", entities));
691
692 static const std::string version = "1.0.0";
693 try_save(ar, ser20::make_nvp("version", version));
694
695 if(!is_root)
696 {
697 const_handle_cast(obj).erase<root_component>();
698 }
699
700 pop_save_context(pushed);
701}
702
703template<typename Archive>
704auto load_from_archive_impl(Archive& ar, entt::registry& registry) -> entt::handle
705{
706 std::vector<entity_data<entt::handle>> entities;
707 try_load(ar, ser20::make_nvp("entities", entities));
708
709 std::string version;
710 try_load(ar, ser20::make_nvp("version", version));
711
712 entt::handle result{};
713 if(!entities.empty())
714 {
715 result = entities.front().components.entity;
716 }
717
718 auto& ctx = engine::context();
719 auto& ev = ctx.get_cached<events>();
720
721 if(ev.is_playing)
722 {
723 auto& rsys = ctx.get_cached<rendering_system>();
724 auto& ssys = ctx.get_cached<script_system>();
725
726 delta_t dt(0.016667f);
727 auto span = as_span(entities);
728 rsys.on_play_begin(span, dt);
729 ssys.on_play_begin(span);
730 }
731
732 return result;
733}
734
735template<typename Archive>
736void load_from_archive_start(Archive& ar, entt::registry& registry, entt::handle& e)
737{
738 bool pushed = push_load_context(registry);
739
740 e = load_from_archive_impl(ar, registry);
741
742 pop_load_context(pushed);
743}
744
745template<typename Archive>
746auto load_from_archive_start(Archive& ar, entt::registry& registry) -> entt::handle
747{
748 bool pushed = push_load_context(registry);
749
750 auto obj = load_from_archive_impl(ar, registry);
751
752 pop_load_context(pushed);
753
754 return obj;
755}
756
757template<typename Archive>
758void load_from_archive(Archive& ar, entt::handle& obj)
759{
760 obj = load_from_archive_start(ar, *obj.registry());
761}
762
763template<typename Archive>
764void save_to_archive(Archive& ar, const entt::registry& reg)
765{
766 bool pushed = push_save_context();
767
768 size_t count = 0;
769 reg.view<root_component, transform_component>().each(
770 [&](auto e, auto&& comp1, auto&& comp2)
771 {
772 count++;
773 });
774
775 try_save(ar, ser20::make_nvp("entities_count", count));
776 reg.view<root_component, transform_component>().each(
777 [&](auto e, auto&& comp1, auto&& comp2)
778 {
779 save_to_archive(ar, entt::const_handle(reg, e));
780 });
781
782 pop_save_context(pushed);
783}
784
785template<typename Archive>
786void load_from_archive(Archive& ar, entt::registry& reg)
787{
788 reg.clear();
789 size_t count = 0;
790 try_load(ar, ser20::make_nvp("entities_count", count));
791
792 bool pushed = push_load_context(reg);
793
794 for(size_t i = 0; i < count; ++i)
795 {
796 entt::handle e(reg, reg.create());
797 load_from_archive(ar, e);
798 }
799
800 pop_load_context(pushed);
801}
802
803} // namespace
804
805void save_to_stream(std::ostream& stream, entt::const_handle obj)
806{
807 if(stream.good())
808 {
809 // APPLOG_INFO_PERF(std::chrono::microseconds);
810
811 try
812 {
813 auto ar = ser20::create_oarchive_associative(stream);
814 save_to_archive(ar, obj);
815 }
816 catch(const ser20::Exception& e)
817 {
818 APPLOG_ERROR("Failed to save entity to stream: {}", e.what());
819 }
820 }
821}
822
823void save_to_file(const std::string& absolute_path, entt::const_handle obj)
824{
825 writing = true;
826 {
827 std::ofstream stream(absolute_path);
828
829 bool pushed = push_save_context();
830 auto& save_ctx = get_save_context();
831 save_ctx.save_source = obj;
832 save_ctx.to_prefab = true;
833
834 save_to_stream(stream, obj);
835
836 save_ctx.to_prefab = false;
837 save_ctx.save_source = {};
838 pop_save_context(pushed);
839 }
840 writing = false;
841}
842
843void save_to_stream_bin(std::ostream& stream, entt::const_handle obj)
844{
845 if(stream.good())
846 {
847 ser20::oarchive_binary_t ar(stream);
848
849 save_to_archive(ar, obj);
850 }
851}
852
853void save_to_file_bin(const std::string& absolute_path, entt::const_handle obj)
854{
855 std::ofstream stream(absolute_path, std::ios::binary);
856
857 bool pushed = push_save_context();
858 auto& save_ctx = get_save_context();
859 save_ctx.save_source = obj;
860 save_ctx.to_prefab = true;
861
862 save_to_stream_bin(stream, obj);
863 save_ctx.to_prefab = false;
864 save_ctx.save_source = {};
865 pop_save_context(pushed);
866}
867
868void load_from_view(std::string_view view, entt::handle& obj)
869{
870 if(!view.empty())
871 {
872 // APPLOG_INFO_PERF(std::chrono::microseconds);
873
874 try
875 {
876 auto ar = ser20::create_iarchive_associative(view.data(), view.size());
877 load_from_archive(ar, obj);
878 }
879 catch(const ser20::Exception& e)
880 {
881 APPLOG_ERROR("Failed to load entity from view: {}", e.what());
882 }
883 }
884}
885
886void load_from_stream(std::istream& stream, entt::handle& obj)
887{
888 if(stream.good())
889 {
890 // APPLOG_INFO_PERF(std::chrono::microseconds);
891 try
892 {
893 auto ar = ser20::create_iarchive_associative(stream);
894 load_from_archive(ar, obj);
895 }
896 catch(const ser20::Exception& e)
897 {
898 APPLOG_ERROR("Failed to load entity from stream: {}", e.what());
899 }
900 }
901}
902
903void load_from_file(const std::string& absolute_path, entt::handle& obj)
904{
905 std::ifstream stream(absolute_path);
906 load_from_stream(stream, obj);
907}
908
909void load_from_stream_bin(std::istream& stream, entt::handle& obj)
910{
911 if(stream.good())
912 {
913 // APPLOG_INFO_PERF(std::chrono::microseconds);
914 try
915 {
916 ser20::iarchive_binary_t ar(stream);
917 load_from_archive(ar, obj);
918 }
919 catch(const ser20::Exception& e)
920 {
921 APPLOG_ERROR("Failed to load entity from stream: {}", e.what());
922 }
923 }
924}
925
926void load_from_file_bin(const std::string& absolute_path, entt::handle& obj)
927{
928 // APPLOG_INFO_PERF(std::chrono::microseconds);
929
930 std::ifstream stream(absolute_path, std::ios::binary);
931 load_from_stream_bin(stream, obj);
932}
933
935 entt::registry& registry,
936 entt::handle& obj) -> bool
937{
938 reading = true;
939 bool result = true;
940
941 // copy here to keep it alive
942 auto prefab = pfb.get();
943 const auto& buffer = prefab->buffer.data;
944
945 if(!buffer.empty())
946 {
947 // APPLOG_INFO_PERF(std::chrono::microseconds);
948
949 try
950 {
951 auto ar = ser20::create_iarchive_associative(buffer.data(), buffer.size());
952
953 bool pushed = push_load_context(registry);
954
955 auto& load_ctx = get_load_context();
956
958
959 load_from_archive_start(ar, registry, obj);
960
962
963 pop_load_context(pushed);
964
965
966 if(obj)
967 {
968 auto& pfb_comp = obj.get_or_emplace<prefab_component>();
969 pfb_comp.source = pfb;
970 }
971 }
972 catch(const ser20::Exception& e)
973 {
974 result = false;
975 bool r = reading;
976 bool w = writing;
977 APPLOG_ERROR("Broken prefab {}", pfb.id());
978 }
979 }
980
981 reading = false;
982 return result;
983}
984
985auto load_from_prefab(const asset_handle<prefab>& pfb, entt::registry& registry) -> entt::handle
986{
987 reading = true;
988 entt::handle obj;
989
990 // copy here to keep it alive
991 auto prefab = pfb.get();
992 const auto& buffer = prefab->buffer.data;
993
994 if(!buffer.empty())
995 {
996 // APPLOG_INFO_PERF(std::chrono::microseconds);
997
998 try
999 {
1000 auto ar = ser20::create_iarchive_associative(buffer.data(), buffer.size());
1001
1002 obj = load_from_archive_start(ar, registry);
1003
1004
1005 if(obj)
1006 {
1007 auto& pfb_comp = obj.get_or_emplace<prefab_component>();
1008 pfb_comp.source = pfb;
1009 }
1010 }
1011 catch(const ser20::Exception& e)
1012 {
1013 bool r = reading;
1014 bool w = writing;
1015 APPLOG_ERROR("Broken prefab {}", pfb.id());
1016 }
1017 }
1018
1019 reading = false;
1020
1021 return obj;
1022}
1023auto load_from_prefab_bin(const asset_handle<prefab>& pfb, entt::registry& registry) -> entt::handle
1024{
1025 entt::handle obj;
1026
1027 // copy here to keep it alive
1028 auto prefab = pfb.get();
1029 auto buffer = prefab->buffer.get_stream_buf();
1030 std::istream stream(&buffer);
1031 if(stream.good())
1032 {
1033 // APPLOG_INFO_PERF(std::chrono::microseconds);
1034
1035 try
1036 {
1037 ser20::iarchive_binary_t ar(stream);
1038
1039 obj = load_from_archive_start(ar, registry);
1040
1041 if(obj)
1042 {
1043 auto& pfb_comp = obj.get_or_emplace<prefab_component>();
1044 pfb_comp.source = pfb;
1045 }
1046 }
1047 catch(const ser20::Exception& e)
1048 {
1049 APPLOG_ERROR("Broken prefab {}", pfb.id());
1050 }
1051 }
1052
1053 return obj;
1054}
1055
1056void clone_entity_from_stream(entt::const_handle src_obj, entt::handle& dst_obj)
1057{
1058 // APPLOG_INFO_PERF(std::chrono::microseconds);
1059
1060 bool is_prefab_instance = src_obj.all_of<prefab_component>();
1061
1062 auto clone_mode = is_prefab_instance ? clone_mode_t::cloning_prefab_instance : clone_mode_t::cloning_object;
1063 bool pushed = push_save_context();
1064 auto& save_ctx = get_save_context();
1065 save_ctx.save_source = src_obj;
1066 save_ctx.to_prefab = false;
1067 save_ctx.clone_mode = clone_mode;
1068
1069 //std::stringstream ss;
1070 //std::fstream ss("./clone.ecs", std::ios::out | std::ios::in);
1071 {
1072 std::ofstream ss("./clone.ecs");
1073 save_to_stream(ss, src_obj);
1074 }
1075
1076 save_ctx.to_prefab = false;
1077 save_ctx.save_source = {};
1078 save_ctx.clone_mode = clone_mode_t::none;
1079 pop_save_context(pushed);
1080
1081
1082 pushed = push_load_context(*dst_obj.registry());
1083 auto& load_ctx = get_load_context();
1084 load_ctx.clone_mode = clone_mode;
1085
1086 {
1087 std::ifstream ss("./clone.ecs");
1088 load_from(ss, dst_obj);
1089 }
1090
1091 load_ctx.clone_mode = clone_mode_t::none;
1092 pop_load_context(pushed);
1093}
1094
1095void save_to_stream(std::ostream& stream, const scene& scn)
1096{
1097 if(stream.good())
1098 {
1099 // APPLOG_INFO_PERF(std::chrono::microseconds);
1100
1101 try
1102 {
1103 auto ar = ser20::create_oarchive_associative(stream);
1104 save_to_archive(ar, *scn.registry);
1105 }
1106 catch(const ser20::Exception& e)
1107 {
1108 APPLOG_ERROR("Failed to save scene to stream: {}", e.what());
1109 }
1110 }
1111}
1112void save_to_file(const std::string& absolute_path, const scene& scn)
1113{
1114 // APPLOG_INFO_PERF(std::chrono::microseconds);
1115
1116 std::ofstream stream(absolute_path);
1117 save_to_stream(stream, scn);
1118}
1119void save_to_stream_bin(std::ostream& stream, const scene& scn)
1120{
1121 if(stream.good())
1122 {
1123 // APPLOG_INFO_PERF(std::chrono::microseconds);
1124
1125 try
1126 {
1127 ser20::oarchive_binary_t ar(stream);
1128 save_to_archive(ar, *scn.registry);
1129 }
1130 catch(const ser20::Exception& e)
1131 {
1132 APPLOG_ERROR("Failed to save scene to stream: {}", e.what());
1133 }
1134 }
1135}
1136void save_to_file_bin(const std::string& absolute_path, const scene& scn)
1137{
1138 std::ofstream stream(absolute_path, std::ios::binary);
1139 save_to_stream_bin(stream, scn);
1140}
1141
1142void load_from_view(std::string_view view, scene& scn)
1143{
1144 if(!view.empty())
1145 {
1146 // APPLOG_INFO_PERF(std::chrono::microseconds);
1147
1148 try
1149 {
1150 auto ar = ser20::create_iarchive_associative(view.data(), view.size());
1151 load_from_archive(ar, *scn.registry);
1152 }
1153 catch(const ser20::Exception& e)
1154 {
1155 APPLOG_ERROR("Failed to load scene from view: {}", e.what());
1156 }
1157 }
1158}
1159
1160void load_from_stream(std::istream& stream, scene& scn)
1161{
1162 if(stream.good())
1163 {
1164 // APPLOG_INFO_PERF(std::chrono::microseconds);
1165
1166 stream.seekg(0);
1167
1168 try
1169 {
1170 auto ar = ser20::create_iarchive_associative(stream);
1171 load_from_archive(ar, *scn.registry);
1172 }
1173 catch(const ser20::Exception& e)
1174 {
1175 APPLOG_ERROR("Failed to load scene from stream: {}", e.what());
1176 }
1177 }
1178}
1179void load_from_file(const std::string& absolute_path, scene& scn)
1180{
1181 // APPLOG_INFO_PERF(std::chrono::microseconds);
1182
1183 std::ifstream stream(absolute_path);
1184 load_from_stream(stream, scn);
1185}
1186void load_from_stream_bin(std::istream& stream, scene& scn)
1187{
1188 if(stream.good())
1189 {
1190 // APPLOG_INFO_PERF(std::chrono::microseconds);
1191
1192 stream.seekg(0);
1193
1194 try
1195 {
1196 ser20::iarchive_binary_t ar(stream);
1197 load_from_archive(ar, *scn.registry);
1198 }
1199 catch(const ser20::Exception& e)
1200 {
1201 APPLOG_ERROR("Failed to load scene from stream: {}", e.what());
1202 }
1203 }
1204}
1205void load_from_file_bin(const std::string& absolute_path, scene& scn)
1206{
1207 // APPLOG_INFO_PERF(std::chrono::microseconds);
1208
1209 std::ifstream stream(absolute_path, std::ios::binary);
1210 load_from_stream_bin(stream, scn);
1211}
1212
1214{
1215 // copy here to keep it alive
1216 auto prefab = pfb.get();
1217 const auto& buffer = prefab->buffer.data;
1218
1219 if(!buffer.empty())
1220 {
1221 // APPLOG_INFO_PERF(std::chrono::microseconds);
1222 try
1223 {
1224 auto ar = ser20::create_iarchive_associative(buffer.data(), buffer.size());
1225 load_from_archive(ar, *scn.registry);
1226 }
1227 catch(const ser20::Exception& e)
1228 {
1229 APPLOG_ERROR("Failed to load scene from prefab: {}", e.what());
1230 }
1231 }
1232
1233 return true;
1234}
1236{
1237 // copy here to keep it alive
1238 auto prefab = pfb.get();
1239 auto buffer = prefab->buffer.get_stream_buf();
1240
1241 // APPLOG_INFO_PERF(std::chrono::microseconds);
1242 std::istream stream(&buffer);
1243 if(!stream.good())
1244 {
1245 return false;
1246 }
1247
1248 load_from_stream_bin(stream, scn);
1249
1250 return true;
1251}
1252
1253void clone_scene_from_stream(const scene& src_scene, scene& dst_scene)
1254{
1255 dst_scene.unload();
1256
1257 auto& src = src_scene.registry;
1258 auto& dst = dst_scene.registry;
1259
1260 // APPLOG_INFO_PERF(std::chrono::microseconds);
1261
1262 src->view<root_component, transform_component>().each(
1263 [&](auto e, auto&& comp1, auto&& comp2)
1264 {
1265 std::stringstream ss;
1266 save_to_stream(ss, src_scene.create_handle(e));
1267
1268 auto e_clone = dst_scene.registry->create();
1269 auto e_clone_obj = dst_scene.create_handle(e_clone);
1270
1271 load_from(ss, e_clone_obj);
1272 });
1273}
1274} // namespace unravel
manifold_type type
Base class for different rendering paths in the ACE framework.
void on_play_begin(hpp::span< const entt::handle > entities, delta_t dt)
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
auto get_children() const noexcept -> const std::vector< entt::handle > &
Gets the child entities.
std::chrono::duration< float > delta_t
std::string name
Definition hub.cpp:27
#define APPLOG_ERROR(...)
Definition logging.h:20
auto get_pretty_name(const meta_type &t) -> std::string
auto get_name(const meta_type &t) -> std::string
Definition yaml.hpp:46
void load_entity(Archive &ar, entt::handle &obj, entity_flags flags)
Definition entity.cpp:356
void save_entity_uid(Archive &ar, const entt::const_handle &obj)
Definition entity.cpp:258
auto load_entity_from_id(Archive &ar, entt::handle &obj, entity_flags flags) -> bool
Definition entity.cpp:286
auto load_entity_from_uid(Archive &ar, entt::handle &obj, entity_flags flags) -> bool
Definition entity.cpp:336
auto create_oarchive_associative(std::ostream &stream)
BinaryInputArchive iarchive_binary_t
auto create_iarchive_associative(std::istream &stream)
auto should_load_component(const entt::handle &obj) -> bool
Definition entity.cpp:406
simd::JSONOutputArchive oarchive_associative_t
auto should_save_component(const entt::const_handle &obj) -> bool
Definition entity.cpp:377
BinaryOutputArchive oarchive_binary_t
simd::JSONInputArchive iarchive_associative_t
void save_entity(Archive &ar, const entt::const_handle &obj, entity_flags flags)
Definition entity.cpp:274
void save_entity_id(Archive &ar, const entt::const_handle &obj)
Definition entity.cpp:251
auto get_path_context() -> path_context *
auto push_save_context() -> bool
Definition entity.cpp:90
std::atomic_bool writing
Definition entity.cpp:61
@ resolve_with_loaded
Definition entity.cpp:217
@ resolve_with_existing
Definition entity.cpp:216
auto are_related(entt::const_handle lhs, entt::const_handle rhs) -> bool
Definition entity.cpp:208
void save_to_stream_bin(std::ostream &stream, entt::const_handle obj)
Definition entity.cpp:843
void load_from(Stream &stream, T &scn)
Definition entity.hpp:132
auto push_entity_path(entt::const_handle obj) -> bool
Definition entity.cpp:220
void clone_scene_from_stream(const scene &src_scene, scene &dst_scene)
Definition entity.cpp:1253
void pop_load_context(bool push_result)
Definition entity.cpp:75
void save_to_file_bin(const std::string &absolute_path, const animation_clip &obj)
std::tuple< id_component, tag_component, layer_component, prefab_component, prefab_id_component, transform_component, test_component, model_component, animation_component, bone_component, submesh_component, camera_component, assao_component, tonemapping_component, fxaa_component, ssr_component, light_component, skylight_component, reflection_probe_component, physics_component, audio_source_component, audio_listener_component, text_component, script_component, ui_document_component > all_serializeable_components
auto push_load_context(entt::registry &registry) -> bool
Definition entity.cpp:64
void pop_entity_path(bool pushed)
Definition entity.cpp:234
auto is_parent(entt::const_handle potential_parent, entt::const_handle child) -> bool
Definition entity.cpp:163
thread_local load_context * load_ctx_ptr
Definition entity.cpp:59
auto get_save_context() -> save_context &
Definition entity.cpp:111
void load_from_file(const std::string &absolute_path, animation_clip &obj)
auto get_load_context() -> load_context &
Definition entity.cpp:84
void save_to_file(const std::string &absolute_path, const animation_clip &obj)
std::atomic_bool reading
Definition entity.cpp:62
auto load_from_prefab_bin(const asset_handle< prefab > &pfb, entt::registry &registry) -> entt::handle
Definition entity.cpp:1023
void add_to_uid_mapping(entt::handle &obj, bool recursive=true)
Definition entity.cpp:116
auto load_from_stream(std::istream &stream, entt::handle e, script_component::script_object &obj) -> bool
void load_from_stream_bin(std::istream &stream, entt::handle &obj)
Definition entity.cpp:909
auto load_from_prefab_out(const asset_handle< prefab > &pfb, entt::registry &registry, entt::handle &obj) -> bool
Definition entity.cpp:934
thread_local save_context * save_ctx_ptr
Definition entity.cpp:60
void load_from_file_bin(const std::string &absolute_path, animation_clip &obj)
void pop_save_context(bool push_result)
Definition entity.cpp:101
auto find_root(entt::const_handle e) -> entt::const_handle
Definition entity.cpp:192
auto const_handle_cast(entt::const_handle chandle) -> entt::handle
Definition entity.cpp:26
void load_from_view(std::string_view view, entt::handle &obj)
Definition entity.cpp:868
auto as_span(const std::vector< entity_data< entt::handle > > &entities) -> hpp::span< const entt::handle >
Definition entity.cpp:44
void cleanup_uid_mapping()
Definition entity.cpp:148
auto load_from_prefab(const asset_handle< prefab > &pfb, entt::registry &registry) -> entt::handle
Definition entity.cpp:985
void clone_entity_from_stream(entt::const_handle src_obj, entt::handle &dst_obj)
Definition entity.cpp:1056
auto save_to_stream(std::ostream &stream, entt::const_handle e, const script_component::script_object &obj) -> bool
#define SAVE_INSTANTIATE(cls, Archive)
#define LOAD(cls)
auto try_save(Archive &ar, ser20::NameValuePair< T > &&t, const hpp::source_location &loc=hpp::source_location::current()) -> bool
auto try_serialize_direct(Archive &ar, ser20::NameValuePair< T > &&t, const hpp::source_location &loc=hpp::source_location::current()) -> bool
#define LOAD_INSTANTIATE(cls, Archive)
#define LOAD_FUNCTION_NAME
auto serialize_check(const std::string &name, F &&serialize_callback) -> bool
#define SAVE(cls)
auto try_load(Archive &ar, ser20::NameValuePair< T > &&t, const hpp::source_location &loc=hpp::source_location::current()) -> bool
#define SAVE_FUNCTION_NAME
Represents a handle to an asset, providing access and management functions.
auto get_stream_buf() const -> membuf
Definition filesystem.h:36
static auto context() -> rtti::context &
Definition engine.cpp:115
entity_components< Entity > components
Definition entity.cpp:41
Component that provides a unique identifier (UUID) for an entity.
entt::registry * reg
Definition entity.hpp:58
Component that holds a reference to a prefab asset and tracks property overrides.
asset_handle< prefab > source
Handle to the prefab asset.
Component that provides a unique identifier (UUID) for a prefab.
Represents a generic prefab with a buffer for serialized data.
Definition prefab.h:18
fs::stream_buffer< std::vector< uint8_t > > buffer
Buffer to store serialized data of the prefab.
Definition prefab.h:22
Root component structure for the ACE framework, serves as the base component.
Represents a scene in the ACE framework, managing entities and their relationships.
Definition scene.h:21
void unload()
Unloads the scene, removing all entities.
Definition scene.cpp:169
std::unique_ptr< entt::registry > registry
The registry that manages all entities in the scene.
Definition scene.h:117
auto create_handle(entt::entity e) -> entt::handle
Creates an entity in the scene.
Definition scene.cpp:304
gfx::uniform_handle handle
Definition uniform.cpp:9
YAML input and output archives.