Unravel Engine C++ Reference
Loading...
Searching...
No Matches
entity_actions.cpp
Go to the documentation of this file.
1#include "entity_actions.h"
6#include <engine/ecs/scene.h>
17#include <engine/engine.h>
20
21namespace unravel
22{
23
24namespace
25{
26auto restore_root_from_serialized_subtree(entt::registry& registry, std::string_view blob) -> entt::handle
27{
28 if(blob.empty())
29 {
30 return {};
31 }
32 entt::entity stub = registry.create();
33 entt::handle handle(registry, stub);
34 try
35 {
37 }
38 catch(const std::exception&)
39 {
40 registry.destroy(stub);
41 return {};
42 }
43 if(handle)
44 {
45 if(handle.entity() != stub)
46 {
47 registry.destroy(stub);
48 }
49 return handle;
50 }
51 registry.destroy(stub);
52 return {};
53}
54
55void collect_subtree_uuid_preorder(entt::const_handle obj, std::vector<hpp::uuid>& out)
56{
57 if(!obj)
58 {
59 return;
60 }
61 auto& trans_comp = obj.get<transform_component>();
62 auto* id_comp = obj.try_get<id_component>();
63 if(!id_comp || id_comp->id.is_nil())
64 {
65 return;
66 }
67 out.push_back(id_comp->id);
68 for(auto child : trans_comp.get_children())
69 {
70 collect_subtree_uuid_preorder(child, out);
71 }
72}
73
74void apply_subtree_uuid_preorder(entt::handle obj, const std::vector<hpp::uuid>& uids, size_t& next)
75{
76 if(!obj || next >= uids.size())
77 {
78 return;
79 }
80 auto& trans_comp = obj.get<transform_component>();
81 auto& id_comp = obj.get_or_emplace<id_component>();
82 id_comp.id = uids[next++];
83 for(auto child : trans_comp.get_children())
84 {
85 apply_subtree_uuid_preorder(child, uids, next);
86 }
87}
88} // namespace
89
90create_entities_action_t::create_entities_action_t(std::function<std::vector<entt::handle>()> factory_fn)
91 : factory(std::move(factory_fn))
92{
93 name = "Create Entities";
94}
95
96create_entities_action_t::create_entities_action_t(std::function<entt::handle()> factory_fn)
97{
98 name = "Create Entity";
99 auto single = std::move(factory_fn);
100 factory = [single = std::move(single)]() -> std::vector<entt::handle>
101 {
102 auto ent = single ? single() : entt::handle{};
103 if(!ent)
104 {
105 return {};
106 }
107 return {ent};
108 };
109}
110
112{
113 if(!captured)
114 {
115 if(!factory)
116 {
117 return;
118 }
119
120 auto produced = factory();
121 // Collapse to top-level only in case the factory returns a redundant parent/child pair.
122 auto roots = transform_component::get_top_level_entities(produced);
123
124 serialized_roots.reserve(roots.size());
125 root_entities.reserve(roots.size());
126 parent_entities.reserve(roots.size());
127 subtree_uuids.reserve(roots.size());
128
129 for(auto root : roots)
130 {
131 if(!root)
132 {
133 continue;
134 }
135 auto* id_comp = root.try_get<id_component>();
136 if(!id_comp || id_comp->id.is_nil())
137 {
138 continue;
139 }
140
141 entt::uhandle parent_uh{};
142 if(auto* tr = root.try_get<transform_component>())
143 {
144 auto parent = tr->get_parent();
145 if(parent && parent.try_get<id_component>())
146 {
147 parent_uh = entt::make_uhandle(parent);
148 }
149 }
150
151 subtree_uuids.emplace_back();
152 collect_subtree_uuid_preorder(static_cast<entt::const_handle>(root), subtree_uuids.back());
153 if(subtree_uuids.back().empty())
154 {
155 subtree_uuids.pop_back();
156 continue;
157 }
158
159 std::stringstream ss;
160 save_to_stream(ss, static_cast<entt::const_handle>(root));
161 serialized_roots.emplace_back(ss.str());
162 root_entities.emplace_back(entt::make_uhandle(root));
163 parent_entities.emplace_back(parent_uh);
164 }
165
166 captured = true;
167 // Release any state held by the factory - subsequent redos restore from the snapshot.
168 factory = {};
169 return;
170 }
171
172 // Redo path: recreate each root from its serialized snapshot (mirrors delete_entities_action_t::undo_action).
173 if(root_entities.empty() || !root_entities.front().registry || serialized_roots.empty())
174 {
175 return;
176 }
177 entt::registry& registry = *root_entities.front().registry;
178 for(size_t i = 0; i < serialized_roots.size(); ++i)
179 {
180 auto restored = restore_root_from_serialized_subtree(registry, serialized_roots[i]);
181 if(!restored || i >= parent_entities.size())
182 {
183 continue;
184 }
185 if(i < subtree_uuids.size() && !subtree_uuids[i].empty())
186 {
187 size_t next_uid = 0;
188 apply_subtree_uuid_preorder(restored, subtree_uuids[i], next_uid);
189 }
190 const auto& parent_uh = parent_entities[i];
191 if(!parent_uh.registry || parent_uh.uuid.is_nil())
192 {
193 continue;
194 }
195 auto* tr = restored.try_get<transform_component>();
196 if(!tr)
197 {
198 continue;
199 }
200 auto desired_parent = parent_uh.resolve();
201 if(!desired_parent)
202 {
203 continue;
204 }
205 auto current_parent = tr->get_parent();
206 if(!current_parent || current_parent != desired_parent)
207 {
208 tr->set_parent(desired_parent, false);
209 }
210 }
211}
212
214{
215 if(!captured)
216 {
217 return;
218 }
219
220 auto& ctx = engine::context();
221 auto& em = ctx.get_cached<editing_manager>();
222
223 // Re-snapshot each root before destroying it so that any out-of-band edits made since creation
224 // (or since the last redo) are preserved on the next redo - parent may also have changed.
225 for(size_t i = 0; i < root_entities.size(); ++i)
226 {
227 auto target = root_entities[i].resolve();
228 if(!target)
229 {
230 continue;
231 }
232
233 entt::uhandle parent_uh{};
234 if(auto* tr = target.try_get<transform_component>())
235 {
236 auto parent = tr->get_parent();
237 if(parent && parent.try_get<id_component>())
238 {
239 parent_uh = entt::make_uhandle(parent);
240 }
241 }
242 if(i < parent_entities.size())
243 {
244 parent_entities[i] = parent_uh;
245 }
246
247 if(i < subtree_uuids.size())
248 {
249 subtree_uuids[i].clear();
250 collect_subtree_uuid_preorder(static_cast<entt::const_handle>(target), subtree_uuids[i]);
251 }
252 if(i < serialized_roots.size())
253 {
254 std::stringstream ss;
255 save_to_stream(ss, static_cast<entt::const_handle>(target));
256 serialized_roots[i] = ss.str();
257 }
258
259 em.unselect(target);
261 target.destroy();
262 }
263}
264
265auto create_entities_action_t::is_mergeable(const editing_action_t& /*previous*/) const -> bool
266{
267 return false;
268}
269
271{
272 if(!captured)
273 {
274 // Pre-execution: valid as long as we have a factory to run.
275 return static_cast<bool>(factory);
276 }
277 if(serialized_roots.empty() || serialized_roots.size() != root_entities.size()
278 || parent_entities.size() != root_entities.size())
279 {
280 return false;
281 }
282 if(subtree_uuids.size() != serialized_roots.size())
283 {
284 return false;
285 }
286 for(const auto& root_uh : root_entities)
287 {
288 if(!root_uh.registry || root_uh.uuid.is_nil())
289 {
290 return false;
291 }
292 }
293 for(const auto& uids : subtree_uuids)
294 {
295 if(uids.empty())
296 {
297 return false;
298 }
299 }
300 return true;
301}
302
303delete_entities_action_t::delete_entities_action_t(std::vector<entt::handle> entities)
304{
305 name = "Delete Entities";
306 if(entities.empty())
307 {
308 return;
309 }
310
311 auto roots = transform_component::get_top_level_entities(entities);
312 serialized_roots.reserve(roots.size());
313 root_entities.reserve(roots.size());
314 parent_entities.reserve(roots.size());
315 subtree_uuids.reserve(roots.size());
316 for(auto root : roots)
317 {
318 if(!root)
319 {
320 continue;
321 }
322 auto* id_comp = root.try_get<id_component>();
323 if(!id_comp || id_comp->id.is_nil())
324 {
325 continue;
326 }
327 entt::uhandle parent_uh{};
328 if(auto* tr = root.try_get<transform_component>())
329 {
330 auto parent = tr->get_parent();
331 if(parent && parent.try_get<id_component>())
332 {
333 parent_uh = entt::make_uhandle(parent);
334 }
335 }
336 subtree_uuids.emplace_back();
337 collect_subtree_uuid_preorder(static_cast<entt::const_handle>(root), subtree_uuids.back());
338 if(subtree_uuids.back().empty())
339 {
340 subtree_uuids.pop_back();
341 continue;
342 }
343 std::stringstream ss;
344 save_to_stream(ss, static_cast<entt::const_handle>(root));
345 serialized_roots.emplace_back(ss.str());
346 root_entities.emplace_back(entt::make_uhandle(root));
347 parent_entities.emplace_back(parent_uh);
348 }
349}
350
352{
353 if(!is_valid())
354 {
355 return;
356 }
357 auto& ctx = engine::context();
358 auto& em = ctx.get_cached<editing_manager>();
359 for(const auto& root_uh : root_entities)
360 {
361 auto target = root_uh.resolve();
362 if(!target)
363 {
364 continue;
365 }
366 em.unselect(target);
368 target.destroy();
369 }
370}
371
373{
374 if(root_entities.empty() || !root_entities.front().registry || serialized_roots.empty())
375 {
376 return;
377 }
378 entt::registry& registry = *root_entities.front().registry;
379 for(size_t i = 0; i < serialized_roots.size(); ++i)
380 {
381 auto restored = restore_root_from_serialized_subtree(registry, serialized_roots[i]);
382 if(!restored || i >= parent_entities.size())
383 {
384 continue;
385 }
386 if(i < subtree_uuids.size() && !subtree_uuids[i].empty())
387 {
388 size_t next_uid = 0;
389 apply_subtree_uuid_preorder(restored, subtree_uuids[i], next_uid);
390 }
391 const auto& parent_uh = parent_entities[i];
392 if(!parent_uh.registry || parent_uh.uuid.is_nil())
393 {
394 continue;
395 }
396 auto* tr = restored.try_get<transform_component>();
397 if(!tr)
398 {
399 continue;
400 }
401 auto desired_parent = parent_uh.resolve();
402 if(!desired_parent)
403 {
404 continue;
405 }
406 auto current_parent = tr->get_parent();
407 if(!current_parent || current_parent != desired_parent)
408 {
409 tr->set_parent(desired_parent, false);
410 }
411 }
412}
413
415{
416 if(serialized_roots.empty() || serialized_roots.size() != root_entities.size()
417 || parent_entities.size() != root_entities.size())
418 {
419 return false;
420 }
421 if(subtree_uuids.size() != serialized_roots.size())
422 {
423 return false;
424 }
425 for(const auto& root_uh : root_entities)
426 {
427 if(!root_uh.registry || root_uh.uuid.is_nil())
428 {
429 return false;
430 }
431 }
432 for(const auto& uids : subtree_uuids)
433 {
434 if(uids.empty())
435 {
436 return false;
437 }
438 }
439 return true;
440}
441
443{
444 return false;
445}
446
447entity_add_component_action_t::entity_add_component_action_t(entt::handle ent, const entt::meta_type& ctype)
448 : entity(entt::make_uhandle(ent)), component_type(ctype)
449{
450 name = "Add Component " + entt::get_pretty_name(component_type);
451}
452
454{
455 if(auto ent = entity.resolve())
456 {
457 do_was_successful = component_type.invoke("component_add"_hs, {}, ent).cast<bool>();
458 }
459}
460
462{
463 if(auto ent = entity.resolve())
464 {
465 component_type.invoke("component_remove"_hs, {}, ent);
466 }
467}
468
470{
471 return false;
472}
473
475{
476 auto ent = entity.resolve();
477 return ent.valid() && component_type;
478}
479
481{
482 //draw_in_inspector_impl(ctx, component_type, component_type, {});
483}
484
485entity_remove_component_action_t::entity_remove_component_action_t(entt::handle ent, const entt::meta_type& ctype)
486 : entity(entt::make_uhandle(ent)), component_type(ctype)
487{
488 name = "Remove Component " + entt::get_pretty_name(component_type);
489}
490
492{
493 if(auto ent = entity.resolve())
494 {
495 stream = {};
496 component_type.invoke("component_save"_hs, {}, ent, entt::forward_as_meta(stream));
497 do_was_successful = component_type.invoke("component_remove"_hs, {}, ent).cast<bool>();
498 }
499}
500
502{
503 if(auto ent = entity.resolve())
504 {
505 component_type.invoke("component_add"_hs, {}, ent);
506 stream.seekg(0);
507 component_type.invoke("component_load"_hs, {}, ent, entt::forward_as_meta(stream));
508 }
509}
510
512{
513 return false;
514}
515
517{
518 auto ent = entity.resolve();
519 return ent.valid() && component_type;
520}
521
523{
524 //draw_in_inspector_impl(ctx, component_type, component_type, {});
525}
526
527// Transform Move Action Implementation
528entity_set_active_action_t::entity_set_active_action_t(entt::handle ent, bool old_active, bool new_active)
529 : entity(entt::make_uhandle(ent)), old_active(old_active), new_active(new_active)
530{
531 name = "Set Active";
532}
533
535{
536 if(auto ent = entity.resolve())
537 {
538 if(auto transform = ent.try_get<transform_component>())
539 {
540 transform->set_active(new_active);
542 }
543 }
544}
545
547{
548 if(auto ent = entity.resolve())
549 {
550 if(auto transform = ent.try_get<transform_component>())
551 {
552 transform->set_active(old_active);
554 }
555 }
556}
557
559{
560 const auto& prev = static_cast<const entity_set_active_action_t&>(previous);
561 return entity == prev.entity;
562}
563
565{
566 const auto& prev = static_cast<const entity_set_active_action_t&>(previous);
567 old_active = prev.old_active;
568}
569
571{
572 auto ent = entity.resolve();
573 return ent.valid() && ent.try_get<transform_component>();
574}
575
577{
578 draw_in_inspector_impl(ctx, old_active, new_active, {});
579}
580
581entity_set_name_action_t::entity_set_name_action_t(entt::handle ent, const std::string& old_name, const std::string& new_name)
582 : entity(entt::make_uhandle(ent)), old_name(old_name), new_name(new_name)
583{
584 name = "Set Name";
585}
586
588{
589 if(auto ent = entity.resolve())
590 {
591 if(auto tag = ent.try_get<tag_component>())
592 {
593 tag->name = new_name;
594 prefab_override_context::mark_property_as_changed(ent, entt::resolve<tag_component>(), "name");
595 }
596 }
597}
598
600{
601 if(auto ent = entity.resolve())
602 {
603 if(auto tag = ent.try_get<tag_component>())
604 {
605 tag->name = old_name;
606 prefab_override_context::mark_property_as_changed(ent, entt::resolve<tag_component>(), "name");
607 }
608 }
609}
610
612{
613 draw_in_inspector_impl(ctx, old_name, new_name, {});
614}
615
617{
618 const auto& prev = static_cast<const entity_set_name_action_t&>(previous);
619 return entity == prev.entity;
620}
621
623{
624 const auto& prev = static_cast<const entity_set_name_action_t&>(previous);
625 old_name = prev.old_name;
626}
627
629{
630 auto ent = entity.resolve();
631 return ent.valid() && ent.try_get<tag_component>();
632}
633
634entity_set_tag_action_t::entity_set_tag_action_t(entt::handle ent, const std::string& old_tag, const std::string& new_tag)
635 : entity(entt::make_uhandle(ent)), old_tag(old_tag), new_tag(new_tag)
636{
637 name = "Set Tag";
638}
639
641{
642 if(auto ent = entity.resolve())
643 {
644 if(auto tag = ent.try_get<tag_component>())
645 {
646 tag->tag = new_tag;
647 prefab_override_context::mark_property_as_changed(ent, entt::resolve<tag_component>(), "tag");
648 }
649 }
650}
651
653{
654 if(auto ent = entity.resolve())
655 {
656 if(auto tag = ent.try_get<tag_component>())
657 {
658 tag->tag = old_tag;
659 prefab_override_context::mark_property_as_changed(ent, entt::resolve<tag_component>(), "tag");
660 }
661 }
662}
663
665{
666 const auto& prev = static_cast<const entity_set_tag_action_t&>(previous);
667 return entity == prev.entity;
668}
669
671{
672 const auto& prev = static_cast<const entity_set_tag_action_t&>(previous);
673 old_tag = prev.old_tag;
674}
675
677{
678 auto ent = entity.resolve();
679 return ent.valid() && ent.try_get<tag_component>();
680}
681
683{
684 draw_in_inspector_impl(ctx, old_tag, new_tag, {});
685}
686
687entity_set_materials_action_t::entity_set_materials_action_t(entt::handle ent, const std::vector<asset_handle<material>>& old_materials, const asset_handle<material>& new_material)
688 : entity(entt::make_uhandle(ent)), old_materials(old_materials)
689{
690 new_materials.resize(old_materials.size(), new_material);
691 name = "Set Materials";
692}
693
695{
696 if(auto ent = entity.resolve(); ent && ent.all_of<model_component>())
697 {
698 auto& model_comp = ent.get<model_component>();
699 auto model_copy = model_comp.get_model();
700 for(size_t i = 0; i < new_materials.size() && i < model_copy.get_materials().size(); ++i)
701 {
702 model_copy.set_material(new_materials[i], i);
703 }
704 model_comp.set_model(model_copy);
706 }
707}
708
710{
711 if(auto ent = entity.resolve(); ent && ent.all_of<model_component>() && !old_materials.empty())
712 {
713 auto& model_comp = ent.get<model_component>();
714 auto model_copy = model_comp.get_model();
715 for(size_t i = 0; i < old_materials.size() && i < model_copy.get_materials().size(); ++i)
716 {
717 model_copy.set_material(old_materials[i], i);
718 }
719 model_comp.set_model(model_copy);
721 }
722}
723
725{
726 const auto& prev = static_cast<const entity_set_materials_action_t&>(previous);
727 return entity == prev.entity;
728}
729
731{
732 const auto& prev = static_cast<const entity_set_materials_action_t&>(previous);
734}
735
737{
738 auto ent = entity.resolve();
739 return ent.valid() && ent.all_of<model_component>() && new_materials.size() == old_materials.size()
740 && new_materials.size() > 0 && new_materials[0].is_valid();
741}
742
744{
745
746 entt::meta_any old_materials_any = old_materials;
747 entt::meta_any new_material_any = new_materials;
748 draw_in_inspector_impl(ctx, old_materials_any, new_material_any, {});
749
750 // For now, we'll keep this simple since materials are complex objects
751 // Could be enhanced to show material names/paths in the future
752}
753
755 : entity(entt::make_uhandle(ent)), old_area(old_area), new_area(new_area)
756{
757 name = "Set Text Bounds";
758}
759
761{
762 if(auto ent = entity.resolve(); ent && ent.all_of<text_component>())
763 {
764 auto text_comp = ent.try_get<text_component>();
765 if(text_comp)
766 {
767 text_comp->set_area(new_area);
769 }
770 }
771}
772
774{
775 if(auto ent = entity.resolve(); ent && ent.all_of<text_component>())
776 {
777 auto text_comp = ent.try_get<text_component>();
778 if(text_comp)
779 {
780 text_comp->set_area(old_area);
782 }
783 }
784}
785
787{
788 const auto& prev = static_cast<const entity_set_text_bounds_action_t&>(previous);
789 return entity == prev.entity;
790}
791
793{
794 const auto& prev = static_cast<const entity_set_text_bounds_action_t&>(previous);
795 old_area = prev.old_area;
796}
797
799{
800 auto ent = entity.resolve();
801 return ent.valid() && ent.all_of<text_component>();
802}
803
805{
806 entt::meta_any old_area_any = old_area;
807 entt::meta_any new_area_any = new_area;
808 draw_in_inspector_impl(ctx, old_area_any, new_area_any, {});
809}
810
811
813 : entity(entt::make_uhandle(ent)), old_size(old_size), new_size(new_size)
814{
815 name = "Set UI Document Component Bounds";
816}
817
819{
820 if(auto ent = entity.resolve(); ent && ent.all_of<ui_document_component>())
821 {
822 auto ui_document_comp = ent.try_get<ui_document_component>();
823 if(ui_document_comp)
824 {
825 ui_document_comp->size = new_size;
827 }
828 }
829}
830
832{
833 if(auto ent = entity.resolve(); ent && ent.all_of<ui_document_component>())
834 {
835 auto ui_document_comp = ent.try_get<ui_document_component>();
836 if(ui_document_comp)
837 {
838 ui_document_comp->size = old_size;
840 }
841 }
842}
843
845{
846 const auto& prev = static_cast<const entity_set_ui_document_component_bounds_action_t&>(previous);
847 return entity == prev.entity;
848}
849
851{
852 const auto& prev = static_cast<const entity_set_ui_document_component_bounds_action_t&>(previous);
853 old_size = prev.old_size;
854}
855
857{
858 auto ent = entity.resolve();
859 return ent.valid() && ent.all_of<ui_document_component>();
860}
861
863{
864 entt::meta_any old_size_any = old_size;
865 entt::meta_any new_size_any = new_size;
866 draw_in_inspector_impl(ctx, old_size_any, new_size_any, {});
867}
868
869// Script component action implementations
871 : entity(entt::make_uhandle(ent)), script_type_name(type_name)
872{
873 name = "Add Script Component " + script_type_name;
874}
875
877{
878 if(auto ent = entity.resolve(); ent && !script_type_name.empty())
879 {
880 auto& ctx = engine::context();
881 auto& script_sys = ctx.get_cached<script_system>();
882 auto script_type = script_sys.get_type_by_fullname(script_type_name);
883
884 if(script_type.valid())
885 {
886 auto script_comp = ent.try_get<script_component>();
887 if(!script_comp)
888 {
889 script_comp = &ent.emplace<script_component>();
890 }
891 auto script_obj = script_comp->add_script_component(script_type);
892 do_was_successful = script_obj.pinned != nullptr;
893 }
894 }
895}
896
898{
899 if(auto ent = entity.resolve(); ent && !script_type_name.empty() && do_was_successful)
900 {
901 auto& ctx = engine::context();
902 auto& script_sys = ctx.get_cached<script_system>();
903 auto script_type = script_sys.get_type_by_fullname(script_type_name);
904
905 if(script_type.valid())
906 {
907 auto script_comp = ent.try_get<script_component>();
908 if(script_comp)
909 {
910 script_comp->remove_script_component(script_type);
911 script_comp->process_pending_deletions();
912 }
913 }
914 }
915}
916
918{
919 return false;
920}
921
923{
924 auto ent = entity.resolve();
925 return ent.valid() && !script_type_name.empty();
926}
927
929{
930 // Could implement visual representation if needed
931}
932
934 : entity(entt::make_uhandle(ent)), script_type_name(type_name), script_index(index)
935{
936 name = "Remove Script Component " + script_type_name;
937 if (index >= 0)
938 {
939 name += " [" + std::to_string(index) + "]";
940 }
941}
942
944{
945 if(auto ent = entity.resolve(); ent && !script_type_name.empty())
946 {
947 auto& ctx = engine::context();
948 auto& script_sys = ctx.get_cached<script_system>();
949 auto script_type = script_sys.get_type_by_fullname(script_type_name);
950
951 if(script_type.valid())
952 {
953 auto script_comp = ent.try_get<script_component>();
954 if (script_comp)
955 {
956 const auto& comps = script_comp->get_script_components();
957
958 // If index is specified and valid, remove the specific component at that index
959 if (script_index >= 0 && script_index < static_cast<int>(comps.size()))
960 {
961 const auto& script_obj = comps[script_index];
962
963 // Verify this is the correct type
964 if (script_obj.pinned)
965 {
966 auto obj = script_obj.pinned->get_object();
967 if(obj.get_type().get_fullname() == script_type_name)
968 {
969 // Serialize the script object before removing it
972
973 // Remove the specific script component instance
974 do_was_successful = script_comp->remove_script_component(obj);
976 {
977 script_comp->process_pending_deletions();
978 }
979 }
980 }
981 }
982 else
983 {
984 // Fallback to old behavior: remove first component of this type
985 auto script_obj = script_comp->get_script_component(script_type);
986 if (script_obj.pinned)
987 {
988 // Serialize the script object before removing it
991 }
992
993 do_was_successful = script_comp->remove_script_component(script_type);
995 {
996 script_comp->process_pending_deletions();
997 }
998 }
999 }
1000 }
1001 }
1002}
1003
1005{
1006 if(auto ent = entity.resolve(); ent && !script_type_name.empty() && do_was_successful)
1007 {
1008 auto& ctx = engine::context();
1009 auto& script_sys = ctx.get_cached<script_system>();
1010 auto script_type = script_sys.get_type_by_fullname(script_type_name);
1011
1012 if(script_type.valid())
1013 {
1014 auto& script_comp = ent.get_or_emplace<script_component>();
1015 if(!removed_script_object_data.str().empty())
1016 {
1017 try
1018 {
1021 load_from_stream(removed_script_object_data, ent, restored_obj);
1022
1023 // Add the restored script object
1024 script_comp.add_script_component(restored_obj);
1025
1026 }
1027 catch(...)
1028 {
1029 // Fallback: create new instance if deserialization fails
1030 script_comp.add_script_component(script_type);
1031 }
1032 }
1033 else
1034 {
1035 // Fallback: create new instance of the type
1036 script_comp.add_script_component(script_type);
1037 }
1038 }
1039 }
1040}
1041
1043{
1044 return false;
1045}
1046
1048{
1049 auto ent = entity.resolve();
1050 return ent.valid() && !script_type_name.empty();
1051}
1052
1054{
1055 // Could implement visual representation if needed
1056}
1057
1058} // namespace unravel
Class that contains core data for meshes.
auto get_model() const -> const model &
Gets the model.
Class that contains core data for audio listeners. There can only be one instance of it per scene.
auto add_script_component(const dotnet::type &type) -> script_object
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
static auto get_top_level_entities(const std::vector< entt::handle > &list) -> std::vector< entt::handle >
auto get_parent() const noexcept -> entt::handle
RELATIONSHIP.
uint16_t index
std::string name
Definition hub.cpp:33
std::string tag
Definition hub.cpp:32
auto make_uhandle(entt::handle handle) -> uhandle
Definition scene.h:229
auto get_pretty_name(const meta_type &t) -> std::string
Hash specialization for batch_key to enable use in std::unordered_map.
auto load_from_stream(std::istream &stream, entt::handle e, script_component::script_object &obj) -> bool
void load_from_view(std::string_view view, entt::handle &obj)
Definition entity.cpp:965
auto save_to_stream(std::ostream &stream, entt::const_handle e, const script_component::script_object &obj) -> bool
utfchar32_t next(octet_iterator &it, octet_iterator end)
Definition checked.h:151
entt::handle entity
fsize_t new_area
Thread-safe handle to an asset.
auto resolve() const -> entt::handle
Definition scene.cpp:486
auto is_mergeable(const editing_action_t &previous) const -> bool override
create_entities_action_t(std::function< std::vector< entt::handle >()> factory)
Multi-root constructor. The factory returns the set of newly-created roots.
std::function< std::vector< entt::handle >()> factory
bool captured
True once the initial factory-driven creation has run and the snapshot is populated.
auto is_valid() const -> bool override
std::vector< entt::uhandle > parent_entities
Parent of each root (may hold a nil uuid for root-level entities). Refreshed on every undo.
std::vector< std::string > serialized_roots
Serialized bytes of each root, captured after the first factory execution.
std::vector< entt::uhandle > root_entities
Handles of each created root; the registry pointer persists even after the entity is destroyed.
std::vector< std::vector< hpp::uuid > > subtree_uuids
Preorder UUIDs per root subtree (same ordering as save_to_stream / flatten_hierarchy).
delete_entities_action_t(std::vector< entt::handle > entities)
std::vector< std::vector< hpp::uuid > > subtree_uuids
Preorder UUIDs per root subtree (same order as save_to_stream / flatten_hierarchy).
std::vector< entt::uhandle > root_entities
std::vector< entt::uhandle > parent_entities
auto is_valid() const -> bool override
auto is_mergeable(const editing_action_t &previous) const -> bool override
std::vector< std::string > serialized_roots
static auto context() -> rtti::context &
Definition engine.cpp:111
void draw_in_inspector(rtti::context &ctx) override
auto is_valid() const -> bool override
entity_add_component_action_t(entt::handle ent, const entt::meta_type &ctype)
auto is_mergeable(const editing_action_t &previous) const -> bool override
void draw_in_inspector(rtti::context &ctx) override
auto is_mergeable(const editing_action_t &previous) const -> bool override
entity_add_script_component_action_t(entt::handle ent, const std::string &type_name)
auto is_mergeable(const editing_action_t &previous) const -> bool override
auto is_valid() const -> bool override
entity_remove_component_action_t(entt::handle ent, const entt::meta_type &ctype)
void draw_in_inspector(rtti::context &ctx) override
entity_remove_script_component_action_t(entt::handle ent, const std::string &type_name, int index=-1)
auto is_mergeable(const editing_action_t &previous) const -> bool override
void draw_in_inspector(rtti::context &ctx) override
void draw_in_inspector(rtti::context &ctx) override
entity_set_active_action_t(entt::handle ent, bool old_active, bool new_active)
void merge_with(const editing_action_t &previous) override
auto is_valid() const -> bool override
auto is_mergeable(const editing_action_t &previous) const -> bool override
std::vector< asset_handle< material > > new_materials
auto is_valid() const -> bool override
std::vector< asset_handle< material > > old_materials
entity_set_materials_action_t(entt::handle ent, const std::vector< asset_handle< material > > &old_materials, const asset_handle< material > &new_material)
void merge_with(const editing_action_t &previous) override
void draw_in_inspector(rtti::context &ctx) override
auto is_mergeable(const editing_action_t &previous) const -> bool override
entity_set_name_action_t(entt::handle ent, const std::string &old_name, const std::string &new_name)
auto is_mergeable(const editing_action_t &previous) const -> bool override
void draw_in_inspector(rtti::context &ctx) override
auto is_valid() const -> bool override
void merge_with(const editing_action_t &previous) override
auto is_mergeable(const editing_action_t &previous) const -> bool override
void merge_with(const editing_action_t &previous) override
entity_set_tag_action_t(entt::handle ent, const std::string &old_tag, const std::string &new_tag)
auto is_valid() const -> bool override
void draw_in_inspector(rtti::context &ctx) override
auto is_mergeable(const editing_action_t &previous) const -> bool override
auto is_valid() const -> bool override
entity_set_text_bounds_action_t(entt::handle ent, const fsize_t &old_area, const fsize_t &new_area)
void merge_with(const editing_action_t &previous) override
void draw_in_inspector(rtti::context &ctx) override
entity_set_ui_document_component_bounds_action_t(entt::handle ent, const usize32_t &old_size, const usize32_t &new_size)
auto is_mergeable(const editing_action_t &previous) const -> bool override
void merge_with(const editing_action_t &previous) override
Component that provides a unique identifier (UUID) for an entity.
static void mark_material_as_changed(entt::handle entity)
Marks material as changed in prefab override system.
static void mark_text_area_as_changed(entt::handle entity)
Marks text area as changed in prefab override system.
static void mark_entity_as_removed(entt::handle entity)
Marks an entity as removed from the prefab instance.
static void mark_ui_document_size_as_changed(entt::handle entity)
static void mark_property_as_changed(entt::handle entity, const entt::meta_type &component_type, const std::string &property_path, const std::string &property_pretty_path={})
Marks a specific property as changed using component type.
static void mark_active_as_changed(entt::handle entity)
Marks entity active state as changed in prefab override system.
auto get_type_by_fullname(const std::string &fullname) const -> dotnet::type
Component that provides a tag (name or label) for an entity.
Component that holds a reference to a UI document for RmlUi rendering.
gfx::uniform_handle handle
Definition uniform.cpp:9