Unravel Engine C++ Reference
Loading...
Searching...
No Matches
editing_manager.cpp
Go to the documentation of this file.
1#include "editing_manager.h"
2#include "base/basetypes.hpp"
4#include "imgui/imgui.h"
5#include "logging/logging.h"
7#include <chrono>
13
14#include <engine/ecs/ecs.h>
16#include <engine/engine.h>
17#include <engine/events.h>
18#include <engine/play_mode.h>
22
25#include <editor/events.h>
29#include <imgui_widgets/gizmo.h>
32
33#include <filedialog/filedialog.h>
34
35namespace unravel
36{
37
38namespace
39{
42 void reload_script_domains(rtti::context& ctx, script_system& scripting, bool recompile)
43 {
44 const bool reload_engine =
45 ctx.has<project_manager>() &&
46 ctx.get_cached<project_manager>().get_editor_settings().scripting.reload_engine_domain;
47
48 scripting.unload_app_domain();
49 if(reload_engine)
50 {
51 scripting.unload_engine_domain();
52 scripting.load_engine_domain(ctx, recompile);
53 }
54 scripting.load_app_domain(ctx, recompile);
55 }
56
57 struct merge_session
58 {
59 uint64_t epoch = 1; // increments on boundaries (press/release/focus loss)
60 bool down_prev = false;
61
62 auto is_active() const -> bool
63 {
64 return ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsAnyItemActive();
65 }
66
67 void tick()
68 {
69 const bool down = is_active();
70
71
72 if(!ImGui::IsAnyItemActive())
73 {
74 // Bump the epoch on any boundary so new actions won't merge with the previous batch.
75 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) ||
76 ImGui::GetIO().AppFocusLost)
77 {
78 ++epoch;
79 }
80
81 if(ImGui::IsMouseReleased(ImGuiMouseButton_Left))
82 {
83 ++epoch;
84
85 }
86 }
87
88
90 }
91
92 // Current merge key to stamp onto actions created this frame.
93 // 0 means "not mergeable".
94 auto current_merge_key() const -> uint64_t
95 {
96 return epoch;
97 }
98 };
99
100 static merge_session session;
101}
102
104{
105 auto& ev = ctx.get_cached<events>();
106
107 ev.on_play_before_begin.connect(sentinel_, 1000, this, &editing_manager::on_play_before_begin);
108 ev.on_play_begin.connect(sentinel_, 1000, this, &editing_manager::on_play_begin);
109 ev.on_play_after_end.connect(sentinel_, -1000, this, &editing_manager::on_play_after_end);
110 ev.on_frame_update.connect(sentinel_, 1000, this, &editing_manager::on_frame_update);
111 ev.on_script_recompile.connect(sentinel_, 1000, this, &editing_manager::on_script_recompile);
112
113 return true;
114}
115
117{
118 unselect();
119 unfocus();
120 return true;
121}
122
124{
125 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
126
127 waiting_for_compilation_before_play_ = true;
128
130 auto& scripting = ctx.get_cached<script_system>();
131
132 {
133 scripting.wait_for_jobs_to_finish(ctx);
134 on_frame_update(ctx, delta_t(0.016667f));
135 }
136
137
139
141 pending_actions.clear();
142
143 save_selection(ctx);
144
145 clear(false);
146
147 const auto& scenes = scene::get_all_scenes();
148 {
149 // APPLOG_TRACE_PERF_NAMED(std::chrono::milliseconds, "save_checkpoints");
150 caches_.clear();
151 for(auto scn : scenes)
152 {
153 auto& cache = caches_[scn->tag];
154 cache.scn = scn;
155 save_checkpoint(ctx, cache);
156 cache.scn = nullptr;
157 }
158 }
159
160
161 // Unload scenes BEFORE unloading domains to prevent script_component destructors
162 // from trying to free GC handles from the old domain
164
165 {
166 scripting.wait_for_jobs_to_finish(ctx);
167 on_frame_update(ctx, delta_t(0.016667f));
168 }
169
170 reload_script_domains(ctx, scripting, true);
171
172 const bool defer_game_scene = ctx.has<settings>() && ctx.get<settings>().splash.enabled;
173
174 {
175 // APPLOG_TRACE_PERF_NAMED(std::chrono::milliseconds, "load_checkpoints");
176
177 for(auto scn : scenes)
178 {
179 if(defer_game_scene && scn->tag == "game")
180 {
181 continue;
182 }
183 auto& cache = caches_[scn->tag];
184 cache.scn = scn;
185 load_checkpoint(ctx, cache, true);
186 cache.scn = nullptr;
187 }
188 }
189
191
192 waiting_for_compilation_before_play_ = false;
193
194}
195
197{
198 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
199
200 if(!ctx.has<settings>() || !ctx.get<settings>().splash.enabled)
201 {
202 return;
203 }
204
205 auto cache_it = caches_.find("game");
206 if(cache_it == caches_.end())
207 {
208 return;
209 }
210
211 for(auto scn : scene::get_all_scenes())
212 {
213 if(scn->tag != "game")
214 {
215 continue;
216 }
217 auto& cache = cache_it->second;
218 cache.scn = scn;
219 load_checkpoint(ctx, cache, true);
220 cache.scn = nullptr;
221 break;
222 }
223}
224
226{
227 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
229
230 unselect();
231
232 auto& scripting = ctx.get_cached<script_system>();
233 {
234 scripting.wait_for_jobs_to_finish(ctx);
235 on_frame_update(ctx, delta_t(0.016667f));
236 }
237
239 pending_actions.clear();
240
241
242 clear(false);
243
244
245 const auto& scenes = scene::get_all_scenes();
246 for(auto scn : scenes)
247 {
248 // GAME scene is not saved. Any changes to it during play will be lost.
249 if(scn->tag == "game")
250 {
251 continue;
252 }
253
254 auto& cache = caches_[scn->tag];
255 cache.scn = scn;
256 save_checkpoint(ctx, cache);
257 cache.scn = nullptr;
258 }
259
260 // Unload scenes BEFORE unloading domains to prevent script_component destructors
261 // from trying to free GC handles from the old domain
263
264 {
265 scripting.wait_for_jobs_to_finish(ctx);
266 on_frame_update(ctx, delta_t(0.016667f));
267 }
268
269 reload_script_domains(ctx, scripting, false);
270
271 for(auto scn : scenes)
272 {
273 auto& cache = caches_[scn->tag];
274 cache.scn = scn;
275 load_checkpoint(ctx, cache, true);
276 cache.scn = nullptr;
277
278 sync_prefab_instances(ctx, scn);
279
280 }
281
283
284 caches_.clear();
285
286 ctx.get_cached<simulation>().set_time_scale(1.0f);
287}
288
289void editing_manager::on_script_recompile(rtti::context& ctx, const std::string& protocol, uint64_t version)
290{
291 queue_action("Script Recompile", [&]() {
292 if(waiting_for_compilation_before_play_)
293 {
294 return;
295 }
297
298 save_selection(ctx);
299
300
302
303 clear(false);
304
305 const auto& scenes = scene::get_all_scenes();
306 caches_.clear();
307 for(auto scn : scenes)
308 {
309 auto& cache = caches_[scn->tag];
310 cache.scn = scn;
311 save_checkpoint(ctx, cache);
312 cache.scn = nullptr;
313 }
314
315 // Unload scenes BEFORE unloading domains to prevent script_component destructors
316 // from trying to free GC handles from the old domain
318
319 auto& scripting = ctx.get_cached<script_system>();
320 reload_script_domains(ctx, scripting, false);
321
322 for(auto scn : scenes)
323 {
324 auto& cache = caches_[scn->tag];
325 cache.scn = scn;
326 load_checkpoint(ctx, cache, true);
327 cache.scn = nullptr;
328 }
329
330 caches_.clear();
332 });
333}
334
335void editing_manager::save_selection(rtti::context& ctx)
336{
337 selection_cache_ = {};
339 {
340 if(sel)
341 {
342 if(sel->valid())
343 {
344 auto& id_comp = sel->get_or_emplace<id_component>();
345 id_comp.generate_if_nil();
346 selection_cache_.uids.emplace_back(id_comp.id);
347 }
348 unselect(*sel);
349 }
350 }
351}
352
353void editing_manager::save_checkpoint(rtti::context& ctx, scene_cache& cache)
354{
355 if(!cache.scn)
356 {
357 return;
358 }
359 // APPLOG_TRACE("save_checkpoint {}", cache.scn->tag);
360
361 cache.cache = {};
362 cache.cache_source = cache.scn->source;
363 // first save scene
364 // APPLOG_TRACE_PERF_NAMED(std::chrono::milliseconds, "save_to_stream");
365
366 save_to_stream(cache.cache, *cache.scn);
367}
368
369void editing_manager::load_checkpoint(rtti::context& ctx, scene_cache& cache, bool recover_selection)
370{
371 if(!cache.scn)
372 {
373 return;
374 }
375
376 // APPLOG_TRACE("load_checkpoint {}", cache.scn->tag);
377 // clear scene
378 cache.scn->unload();
379
380 {
381 // APPLOG_TRACE_PERF_NAMED(std::chrono::milliseconds, "load_from_stream");
382 load_from_stream(cache.cache, *cache.scn);
383 }
384
385 cache.scn->source = cache.cache_source;
386
387 std::vector<entt::handle> entities;
388
389 {
390 // APPLOG_TRACE_PERF_NAMED(std::chrono::milliseconds, "load_checkpoint_selection");
391
392 cache.scn->registry->view<id_component>().each(
393 [&](auto e, auto&& comp)
394 {
395 auto uid = comp.id;
396 if(std::find(selection_cache_.uids.begin(), selection_cache_.uids.end(), uid) != selection_cache_.uids.end())
397 {
398 entities.emplace_back(cache.scn->create_handle(e));
399 }
400 });
401
402 for(auto entity : entities)
403 {
404 if(recover_selection)
405 {
407 }
408 }
409 }
410
411
412 {
413 // APPLOG_TRACE_PERF_NAMED(std::chrono::milliseconds, "load_checkpoint_update");
414 delta_t dt(0.016667f);
415
416 auto& rpath = ctx.get_cached<rendering_system>();
417 rpath.on_frame_update(*cache.scn, dt);
418 rpath.on_frame_before_render(*cache.scn, dt);
419 }
420
421
422 cache.scn = nullptr;
423}
424
426{
427 auto& ctx = engine::context();
428 auto& ec = ctx.get_cached<ecs>();
429 auto& ev = ctx.get_cached<events>();
430
431 auto& play = ctx.get_cached<play_mode>();
432 if(play.is_active())
433 {
434 return;
435 }
436
437
438 const auto& scenes = scene::get_all_scenes();
439 for(auto scn : scenes)
440 {
441
442 std::vector<entt::handle> affected_entities;
443 scn->registry->view<prefab_component>().each(
444 [&](auto e, auto&& prefab_comp)
445 {
446 auto entity = scn->create_handle(e);
447 if(prefab_comp.source == pfb)
448 {
449 affected_entities.emplace_back(entity);
450 }
451 });
452
453 for(auto& entity : affected_entities)
454 {
455 sync_prefab_entity(ctx, entity, pfb);
456 }
457 }
458}
459
461{
462 queue_action("Sync Prefab Entity",
463 [&ctx, entity, pfb]() mutable
464 {
465 auto& ev = ctx.get_cached<events>();
466
467 auto& play = ctx.get_cached<play_mode>();
468 if(play.is_active())
469 {
470 return;
471 }
472
473 if(!entity.valid())
474 {
475 return;
476 }
477
478 if(!pfb.is_valid())
479 {
480 return;
481 }
482
483 if(auto trans_comp = entity.template try_get<transform_component>())
484 {
485 auto parent = trans_comp->get_parent();
486 auto pos = trans_comp->get_position_local();
487 auto rot = trans_comp->get_rotation_local();
488
489 auto& prefab_comp = entity.get<prefab_component>();
490 // Enable path recording for prefab loading
492 path_ctx.should_serialize_property_callback = [&](const std::string& property_path) -> bool
493 {
494 return !prefab_comp.has_serialization_override(property_path);
495 };
496 path_ctx.enable_recording();
499
500
501 if(scene::instantiate_out(*entity.registry(), pfb, entity))
502 {
503 auto& new_trans = entity.get<transform_component>();
504 new_trans.set_position_local(pos);
505 new_trans.set_rotation_local(rot);
506
507 new_trans.set_parent(parent, false);
508 }
509
510
511 // Restore previous path context
513 }
514
515 });
516}
517
519{
520 scn->registry->view<prefab_component>().each(
521 [&](auto e, auto&& comp)
522 {
523 sync_prefab_entity(ctx, comp.get_owner(), comp.source);
524 });
525
526}
527
529{
531
532 if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
533 {
535 }
536 if(ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
537 {
539 }
540
541 return mode;
542}
543
545{
546 session.tick();
547
549
550 if(focused_data.remaining_time > delta_t::zero())
551 {
553 }
554
556
557 if(focused_data.remaining_time <= delta_t::zero())
558 {
559 unfocus();
560 }
561
562 auto& play = ctx.get_cached<play_mode>();
563
564 // Only evict assets if not playing
565 if(!play.is_active())
566 {
567 using namespace std::chrono;
568 static auto last_eviction = steady_clock::now();
569 auto now = steady_clock::now();
570 if(now - last_eviction > seconds(30))
571 {
572 auto& am = ctx.get_cached<asset_manager>();
573 am.evict_unused_assets("app:/", seconds(60));
574 last_eviction = now;
575 }
576 }
577}
578void editing_manager::focus(entt::meta_any object)
579{
582}
583
584void editing_manager::focus_path(const fs::path& object)
585{
587}
588
589void editing_manager::unselect(bool clear_selection_tools)
590{
591 // Capture the old selection state before clearing
592 std::vector<entt::meta_any> old_selection = selection_data.objects;
593
594 // Perform the unselect operation
595 selection_data = {};
596
597 if(clear_selection_tools)
598 {
599 ImGuizmo::Enable(false);
600 ImGuizmo::Enable(true);
601 }
602
603 // Capture the new selection state and create action
604 std::vector<entt::meta_any> new_selection = selection_data.objects;
605
606 // Only create action if selection actually changed
607 bool selection_changed = old_selection.size() != new_selection.size();
608 if (!selection_changed && !old_selection.empty())
609 {
610 // Check if contents are different
611 for (size_t i = 0; i < old_selection.size() && !selection_changed; ++i)
612 {
613 if (i >= new_selection.size() || old_selection[i] != new_selection[i])
614 {
615 selection_changed = true;
616 break;
617 }
618 }
619 }
620
621 if (selection_changed)
622 {
624 queue_action("Unselect", std::make_shared<selection_action_t>(this, old_selection, new_selection, false));
626 }
627}
628
630{
631 focused_data = {};
632}
633
635{
636 auto& play = ctx.get_cached<play_mode>();
637 if(play.is_active())
638 {
639 return;
640 }
641
642
643 auto on_continue = [this,&ctx, prefab]()
644 {
645 // Store the prefab we're editing
648
649 // Clear selection
650 unselect();
651
652 // Create a new scene for prefab editing if it doesn't exist
654
655 // Set up a default 3D scene with lighting
657
658 // Instantiate the prefab in our editing scene
660
661 // Select the prefab entity
662 if (prefab_entity)
663 {
665 }
666
667 APPLOG_INFO("Entered prefab editing mode for: {}", prefab.id());
668 };
669
670 if (is_prefab_mode())
671 {
672 // Already in prefab mode, check if we need to save changes
673 if (edited_prefab != prefab)
674 {
675 auto on_save = [this,&ctx]()
676 {
678 };
679
680 if(auto_save)
681 {
682 on_save();
683 }
684 else
685 {
686 prompt_save_changes(ctx, on_save, on_continue);
687 return;
688 }
689 }
690 else
691 {
693
694 // Already editing this prefab, nothing to do
695 return;
696 }
697 }
698
699 on_continue();
700
701
702}
703
704auto editing_manager::prompt_save_changes(rtti::context& ctx, const std::function<void()>& on_save, const std::function<void()>& on_continue) -> bool
705{
706 ImBox::ShowSaveConfirmation("Save prefab?",
707 "Do you want to save the changes you made?",
708 [&ctx, on_save, on_continue](ImBox::ModalResult result)
709 {
710 if(result == ImBox::ModalResult::Save)
711 {
712 on_save();
713 }
714
715 if(result != ImBox::ModalResult::Cancel)
716 {
717 on_continue();
718 }
719 });
720
721 return true;
722}
723
725{
726 if (!is_prefab_mode())
727 {
728 return;
729 }
730
731 auto on_save = [this,&ctx]()
732 {
734 };
735
736 auto on_continue = [this, &ctx]()
737 {
738 // Reset state
740 edited_prefab = {};
741 prefab_entity = {};
743
744 // Clear selection
745 unselect();
746
747 APPLOG_INFO("Exited prefab editing mode");
748 };
749
750 switch (save_changes)
751 {
752 case save_option::yes:
753 on_save();
754 on_continue();
755 break;
756
757 case save_option::no:
758 on_continue();
759 break;
760
762 prompt_save_changes(ctx, on_save, on_continue);
763 break;
764 }
765
766 // if (should_save)
767 // {
768 // save_prefab_changes(ctx);
769 // }
770
771 // // Reset state
772 // current_mode = editing_mode::scene;
773 // edited_prefab = {};
774 // prefab_entity = {};
775 // prefab_scene.unload();
776
777 // // Clear selection
778 // unselect();
779
780 // APPLOG_INFO("Exited prefab editing mode");
781}
782
784{
786 {
787 return;
788 }
789
790 // Make sure the entity is valid
791 if (!prefab_entity.valid())
792 {
793 APPLOG_ERROR("Failed to save prefab: Invalid entity");
794 ImGui::PushNotification(ImGuiToast(ImGuiToastType_Error, 1000,"Failed to save prefab."));
795
796 return;
797 }
798
799 auto prefab_path = fs::resolve_protocol(edited_prefab.id());
801
802 APPLOG_INFO("Saved changes to prefab: {}", edited_prefab.id());
804
805}
806
807
809{
810 if (is_prefab_mode())
811 {
812 return &prefab_scene;
813 }
814
815 auto& ec = ctx.get_cached<ecs>();
816 return &ec.get_scene();
817
818}
819
820void editing_manager::unload_scenes_scripting(const std::vector<scene*>& scenes)
821{
822 // Only clear script_components to free GC handles before domain unload
823 // Don't unload entire scenes as that destroys rendering resources that
824 // might still be referenced by the graphics system
825 for(auto scn : scenes)
826 {
827 // Clear only script_components to free GC handles
828 // The scenes will be properly unloaded in load_checkpoint
829 scn->registry->clear<script_component>();
830 }
831}
832
833void editing_manager::clear(bool clear_unsaved)
834{
835 if(clear_unsaved)
836 {
838 }
839 unselect();
840 unfocus();
841
842 // Clear pending actions and undo/redo stack
843 pending_actions.clear();
845
846 // If in prefab mode, exit it
847 if (is_prefab_mode())
848 {
849 auto& ctx = engine::context();
851 }
852
853 // Reset prefab editing mode and clean up all references
855 edited_prefab = {};
856 prefab_entity = {};
857
858}
859
860
861void editing_manager::do_action(const std::string& name, const std::function<void()>& action)
862{
864}
865
866void editing_manager::do_action(const std::string& name, const std::function<void()>& do_action, const std::function<void()>& undo_action)
867{
869}
870
871void editing_manager::do_action(const std::string& name, std::shared_ptr<editing_action_t> action)
872{
873 add_action(name, action, true);
874}
875
876void editing_manager::queue_action(const std::string& name, const std::function<void()>& action)
877{
879}
880
881void editing_manager::queue_action(const std::string& name, const std::function<void()>& do_action, const std::function<void()>& undo_action)
882{
884}
885
886void editing_manager::queue_action(const std::string& name, std::shared_ptr<editing_action_t> action)
887{
888 add_action(name, action, false);
889}
890
891
892void editing_manager::add_action(const std::string& name, std::shared_ptr<editing_action_t> action, bool immediate)
893{
894 if (!action)
895 {
896 return;
897 }
898
899 action->merge_key = session.current_merge_key();
900
901 if(!name.empty())
902 {
903 action->name = name;
904 }
905
906 if(undo_stack_enabled.empty())
907 {
908 action->undoable = false;
909 }
910 else
911 {
912 action->undoable = undo_stack_enabled.top();
913 }
914
915 if(!immediate)
916 {
917 action->detach();
918 }
919
920 // Queue the action for execution (don't execute immediately)
921 pending_actions.push_back(std::move(action));
922
923 if(immediate)
924 {
926 }
927}
928
929
931{
932 bool last_enabled = true;
933 if(!undo_stack_enabled.empty())
934 {
935 last_enabled = undo_stack_enabled.top();
936 }
937
938 undo_stack_enabled.push(enabled && last_enabled);
939}
944
946{
947 while(!pending_actions.empty())
948 {
949 auto actions = std::move(pending_actions);
950 // Process all pending actions
951 for (auto& action : actions)
952 {
953 if (action)
954 {
955 // Execute the action
956 action->execution_count++;
957 action->do_action();
958
959 on_action_executed(action);
960 // Add to undo stack if the action is undoable
961 // Note: We need to handle merging here since the action is now executed
962 if (action->is_undoable())
963 {
964 // Move the action to the undo stack
965 undo_stack.push_if_undoable(std::move(action));
966 }
967
968
969 }
970 }
971
972 }
973
974}
975
976auto editing_manager::undo() -> std::shared_ptr<editing_action_t>
977{
978 if (undo_stack.can_undo())
979 {
980 has_unsaved_changes_ = true;
981 return undo_stack.undo();
982 }
983 return nullptr;
984}
985
986auto editing_manager::redo() -> std::shared_ptr<editing_action_t>
987{
988 if (undo_stack.can_redo())
989 {
990 has_unsaved_changes_ = true;
991 return undo_stack.redo();
992 }
993 return nullptr;
994}
995
996void editing_manager::on_action_executed(std::shared_ptr<editing_action_t> action)
997{
998 // Auto-rebuild reflection probes on any scene-mutating action while editing. This mirrors the
999 // experience of Unity/Unreal where moving environment geometry refreshes the bakes in the background.
1000 // We intentionally do nothing in play mode - runtime behavior is governed by probe_update_mode.
1001 if(action->modifies_scene_content())
1002 {
1003 has_unsaved_changes_ = true;
1004
1006 {
1007 auto& ctx = engine::context();
1008 auto& play = ctx.get_cached<play_mode>();
1009 if(!play.is_active())
1010 {
1011 // Time-sliced rebuild so repeated gizmo drags don't stall the editor.
1013 }
1014 }
1015 }
1016}
1017
1018} // namespace unravel
const btCollisionObject * object
Manages assets, including loading, unloading, and storage.
void evict_unused_assets(const std::string &group, std::chrono::steady_clock::duration max_idle)
Evicts full-loaded assets not accessed within the given duration. Demotes them back to deferred state...
Class that contains core data for audio listeners. There can only be one instance of it per scene.
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
void set_position_local(const math::vec3 &position) noexcept
Sets the local position.
std::chrono::duration< float > delta_t
uint64_t epoch
bool down_prev
std::string name
Definition hub.cpp:33
@ ImGuiToastType_Error
@ ImGuiToastType_Success
#define APPLOG_ERROR(...)
Definition logging.h:20
#define APPLOG_INFO(...)
Definition logging.h:18
#define APPLOG_TRACE(...)
Definition logging.h:17
ModalResult
Modal result flags for message box buttons.
auto ShowSaveConfirmation(const std::string &title, const std::string &message, std::function< void(ModalResult)> callback) -> std::shared_ptr< MsgBox >
Show a save confirmation dialog with Save/Don't Save/Cancel buttons.
NOTIFY_INLINE void PushNotification(const ImGuiToast &toast)
Insert a new toast in the list.
path resolve_protocol(const path &_path)
Given the specified path/filename, resolve the final full filename. This will be based on either the ...
void set_path_context(path_context *ctx)
auto get_path_context() -> path_context *
auto atomic_save_to_file(const fs::path &key, const asset_handle< T > &obj) -> bool
auto load_from_stream(std::istream &stream, entt::handle e, script_component::script_object &obj) -> bool
@ immediate
Schedule load on thread pool now (default, backward compatible).
auto save_to_stream(std::ostream &stream, entt::const_handle e, const script_component::script_object &obj) -> bool
entt::handle entity
Thread-safe handle to an asset.
auto is_valid() const -> bool
Checks if the handle references a task.
auto get_cached() -> T &
Definition context.hpp:49
auto has() const -> bool
Definition context.hpp:28
auto get() -> T &
Definition context.hpp:35
std::function< bool(const std::string &)> should_serialize_property_callback
static void create_default_3d_scene_for_editing(rtti::context &ctx, scene &scn)
Creates a default 3D scene for editing.
Manages the entity-component-system (ECS) operations for the ACE framework.
Definition ecs.h:12
auto get_scene() -> scene &
Gets the current scene.
Definition ecs.cpp:30
std::vector< entt::meta_any > objects
auto is_prefab_mode() const -> bool
auto get_active_scene(rtti::context &ctx) -> scene *
void on_play_begin(rtti::context &ctx)
void on_play_after_end(rtti::context &ctx)
auto try_get_selections_as() const -> std::vector< const T * >
auto get_select_mode() const -> select_mode
void push_undo_stack_enabled(bool enabled)
ImGuizmo::MODE mode
current manipulation gizmo space.
void on_action_executed(std::shared_ptr< editing_action_t > action)
void focus_path(const fs::path &object)
auto undo() -> std::shared_ptr< editing_action_t >
auto init(rtti::context &ctx) -> bool
void on_play_before_begin(rtti::context &ctx)
void on_frame_update(rtti::context &ctx, delta_t)
void select(const T &entry, select_mode mode=select_mode::normal, std::string hint="")
void on_script_recompile(rtti::context &ctx, const std::string &protocol, uint64_t version)
void clear(bool clear_unsaved=true)
std::vector< std::shared_ptr< editing_action_t > > pending_actions
void sync_prefab_entity(rtti::context &ctx, entt::handle entity, const asset_handle< prefab > &pfb)
selection selection_data
selection data containing selected object
void queue_action(const std::string &name, const std::function< void()> &action)
void do_action(const std::string &name, const std::function< void()> &action)
auto redo() -> std::shared_ptr< editing_action_t >
void sync_prefab_instances(rtti::context &ctx, scene *scn)
void on_prefab_updated(const asset_handle< prefab > &pfb)
void unload_scenes_scripting(const std::vector< scene * > &scenes)
void enter_prefab_mode(rtti::context &ctx, const asset_handle< prefab > &prefab, bool auto_save=false)
std::stack< bool > undo_stack_enabled
auto deinit(rtti::context &ctx) -> bool
void add_action(const std::string &name, std::shared_ptr< editing_action_t > action, bool immediate=true)
void focus(entt::meta_any object)
Selects an object. Can be anything.
void exit_prefab_mode(rtti::context &ctx, save_option save_changes=save_option::prompt)
void save_prefab_changes(rtti::context &ctx)
asset_handle< prefab > edited_prefab
void unselect(bool clear_selection_tools=true)
Clears the selection data.
static auto rebuild_reflection_probes(rtti::context &ctx, bool force_full_first_frame=true) -> size_t
Flags every reflection probe across all loaded scenes for rebuild.
static auto context() -> rtti::context &
Definition engine.cpp:111
hpp::event< void(rtti::context &)> on_play_before_begin
engine play events
Definition events.h:23
Owns play-mode state and orchestrates the splash -> running lifecycle.
Definition play_mode.h:17
Component that holds a reference to a prefab asset and tracks property overrides.
Represents a generic prefab with a buffer for serialized data.
Definition prefab.h:18
Represents a scene in the ACE framework, managing entities and their relationships.
Definition scene.h:70
auto instantiate_out(const asset_handle< prefab > &pfb, entt::handle &, bool call_callbacks=true) -> bool
Instantiates a prefab in the scene.
Definition scene.cpp:238
static auto get_all_scenes() -> const std::vector< scene * > &
Definition scene.cpp:143
auto instantiate(const asset_handle< prefab > &pfb, bool call_callbacks=true) -> entt::handle
Definition scene.cpp:258
void unload()
Unloads the scene, removing all entities.
Definition scene.cpp:200
std::unique_ptr< entt::registry > registry
The registry that manages all entities in the scene.
Definition scene.h:187
struct unravel::settings::splash_settings splash
Class responsible for timers.
Definition simulation.h:20
void push_if_undoable(std::shared_ptr< editing_action_t > action)
cache_t cache
Definition uniform.cpp:15
bool enabled