Unravel Engine C++ Reference
Loading...
Searching...
No Matches
script_glue.cpp
Go to the documentation of this file.
1#include "script_interop.h"
2#include "script_system.h"
3#include <engine/ecs/ecs.h>
4#include <engine/events.h>
5
6#include <engine/engine.h>
7#include <monopp/mono_exception.h>
8#include <monopp/mono_internal_call.h>
9#include <monopp/mono_jit.h>
10#include <monort/mono_pod_wrapper.h>
11#include <monort/monort.h>
12
15#include <engine/input/input.h>
25#include <graphics/debugdraw.h>
26
27// RmlUi includes
28#include <RmlUi/Core/Element.h>
29#include <RmlUi/Core/ElementDocument.h>
30#include <RmlUi/Core/Variant.h>
31#include <RmlUi/Core/EventListener.h>
32#include <RmlUi/Core/Event.h>
33
34// Mono includes for method invocation
35#include <monopp/mono_method_invoker.h>
36
39#include <logging/logging.h>
40#include <seq/seq.h>
41#include <string_utils/utils.h>
42
43namespace unravel
44{
45namespace
46{
47
48auto get_material_properties(const material::sptr& material) -> mono::managed_interface::material_properties
49{
50 using converter = mono::managed_interface::converter;
51
53
54 if(material->is<pbr_material>())
55 {
56 const auto pbr = std::static_pointer_cast<pbr_material>(material);
57 props.base_color = converter::convert<math::color, mono::managed_interface::color>(pbr->get_base_color());
58 props.emissive_color =
59 converter::convert<math::color, mono::managed_interface::color>(pbr->get_emissive_color());
60 props.tiling = converter::convert<math::vec2, mono::managed_interface::vector2>(pbr->get_tiling());
61 props.roughness = pbr->get_roughness();
62 props.metalness = pbr->get_metalness();
63 props.bumpiness = pbr->get_bumpiness();
64 props.valid = true;
65 }
66
67 return props;
68}
69
70void set_material_properties(const material::sptr& material, const mono::managed_interface::material_properties& props)
71{
72 using converter = mono::managed_interface::converter;
73
74 if(material->is<pbr_material>())
75 {
76 auto pbr = std::static_pointer_cast<pbr_material>(material);
77 auto base_color = converter::convert<mono::managed_interface::color, math::color>(props.base_color);
78 pbr->set_base_color(base_color);
79
80 auto emissive_color = converter::convert<mono::managed_interface::color, math::color>(props.emissive_color);
81 pbr->set_emissive_color(emissive_color);
82
83 auto tiling = converter::convert<mono::managed_interface::vector2, math::vec2>(props.tiling);
84 pbr->set_tiling(tiling);
85
86 pbr->set_metalness(props.metalness);
87
88 pbr->set_bumpiness(props.bumpiness);
89 }
90}
91
92struct mono_asset
93{
94 virtual auto get_asset_uuid(const hpp::uuid& uid) const -> hpp::uuid = 0;
95 virtual auto get_asset_uuid(const std::string& key) const -> hpp::uuid = 0;
96};
97
98template<typename T>
99struct mono_asset_impl : mono_asset
100{
101 auto get_asset_uuid(const hpp::uuid& uid) const -> hpp::uuid override
102 {
103 auto& ctx = engine::context();
104 auto& am = ctx.get_cached<asset_manager>();
105
106 auto asset = am.get_asset<T>(uid);
107 return asset.uid();
108 }
109
110 auto get_asset_uuid(const std::string& key) const -> hpp::uuid override
111 {
112 auto& ctx = engine::context();
113 auto& am = ctx.get_cached<asset_manager>();
114
115 auto asset = am.get_asset<T>(key);
116 return asset.uid();
117 }
118};
119
120auto get_mono_asset(size_t type_hash) -> const mono_asset*
121{
122 // clang-format off
123 static std::map<size_t, std::shared_ptr<mono_asset>> reg =
124 {
125 {mono::mono_type::get_hash("Unravel.Core.Texture"), std::make_shared<mono_asset_impl<gfx::texture>>()},
126 {mono::mono_type::get_hash("Unravel.Core.Material"), std::make_shared<mono_asset_impl<material>>()},
127 {mono::mono_type::get_hash("Unravel.Core.Mesh"), std::make_shared<mono_asset_impl<mesh>>()},
128 {mono::mono_type::get_hash("Unravel.Core.AnimationClip"), std::make_shared<mono_asset_impl<animation_clip>>()},
129 {mono::mono_type::get_hash("Unravel.Core.Prefab"), std::make_shared<mono_asset_impl<prefab>>()},
130 {mono::mono_type::get_hash("Unravel.Core.Scene"), std::make_shared<mono_asset_impl<scene_prefab>>()},
131 {mono::mono_type::get_hash("Unravel.Core.PhysicsMaterial"), std::make_shared<mono_asset_impl<physics_material>>()},
132 {mono::mono_type::get_hash("Unravel.Core.AudioClip"), std::make_shared<mono_asset_impl<audio_clip>>()},
133 {mono::mono_type::get_hash("Unravel.Core.Font"), std::make_shared<mono_asset_impl<font>>()}
134 };
135 // clang-format on
136
137 auto it = reg.find(type_hash);
138 if(it != reg.end())
139 {
140 return it->second.get();
141 }
142 static const mono_asset* empty{};
143 return empty;
144};
145
146auto get_entity_from_id(entt::entity id) -> entt::handle
147{
148 if(id == entt::entity(0))
149 {
150 return {};
151 }
152
153 auto& ctx = engine::context();
154 auto& ec = ctx.get_cached<ecs>();
155
156 return ec.get_scene().create_handle(id);
157}
158
159void raise_invalid_entity_exception()
160{
161 mono::raise_exception("System", "Exception", "Entity is invalid.");
162}
163
164template<typename T>
165void raise_missing_component_exception()
166{
167 mono::raise_exception("System",
168 "Exception",
169 fmt::format("Entity does not have component of type {}.", hpp::type_name_str<T>()));
170}
171
172template<typename T>
173auto safe_get_component(entt::entity id) -> T*
174{
175 auto e = get_entity_from_id(id);
176 if(!e)
177 {
178 raise_invalid_entity_exception();
179 return nullptr;
180 }
181 auto comp = e.try_get<T>();
182
183 if(!comp)
184 {
185 raise_missing_component_exception<T>();
186 return nullptr;
187 }
188
189 return comp;
190}
191
192void internal_m2n_load_scene(const std::string& key)
193{
194 auto delay = seq::delay(1ms);
195 delay.on_end.connect(
196 [key]()
197 {
198 auto& ctx = engine::context();
199 auto& ec = ctx.get_cached<ecs>();
200 auto& am = ctx.get_cached<asset_manager>();
201
202 ec.get_scene().load_from(am.get_asset<scene_prefab>(key));
203 });
204
205 seq::start(delay, "script");
206}
207
208void internal_m2n_load_scene_uid(const hpp::uuid& uid)
209{
210 auto delay = seq::delay(1ms);
211 delay.on_end.connect(
212 [uid]()
213 {
214 auto& ctx = engine::context();
215 auto& ec = ctx.get_cached<ecs>();
216 auto& am = ctx.get_cached<asset_manager>();
217
218 ec.get_scene().load_from(am.get_asset<scene_prefab>(uid));
219 });
220
221 seq::start(delay, "script");
222}
223
224void internal_m2n_create_scene(const mono::mono_object& this_ptr)
225{
226 mono::ignore(this_ptr);
227}
228
229void internal_m2n_destroy_scene(const mono::mono_object& this_ptr)
230{
231 mono::ignore(this_ptr);
232}
233
234auto internal_m2n_create_entity(const std::string& tag) -> entt::entity
235{
236 auto& ctx = engine::context();
237 auto& ec = ctx.get_cached<ecs>();
238
239 auto e = ec.get_scene().create_entity(tag);
240
241 return e.entity();
242}
243
244auto internal_m2n_create_entity_from_prefab_uid(const hpp::uuid& uid) -> entt::entity
245{
246 auto& ctx = engine::context();
247 auto& ec = ctx.get_cached<ecs>();
248 auto& am = ctx.get_cached<asset_manager>();
249
250 auto pfb = am.get_asset<prefab>(uid);
251 auto e = ec.get_scene().instantiate(pfb);
252
253 return e.entity();
254}
255
256auto internal_m2n_create_entity_from_prefab_key(const std::string& key) -> entt::entity
257{
258 auto& ctx = engine::context();
259 auto& ec = ctx.get_cached<ecs>();
260 auto& am = ctx.get_cached<asset_manager>();
261
262 auto pfb = am.get_asset<prefab>(key);
263 auto e = ec.get_scene().instantiate(pfb);
264
265 return e.entity();
266}
267
268auto internal_m2n_clone_entity(entt::entity id) -> entt::entity
269{
270 auto e = get_entity_from_id(id);
271 if(e)
272 {
273 auto& ctx = engine::context();
274 auto& ec = ctx.get_cached<ecs>();
275
276 auto cloned = ec.get_scene().clone_entity(e);
277 return cloned.entity();
278 }
279
280 entt::handle invalid;
281 return invalid.entity();
282}
283
284auto internal_m2n_destroy_entity_immediate(entt::entity id) -> bool
285{
286 auto e = get_entity_from_id(id);
287 if(e)
288 {
289 e.destroy();
290 return true;
291 }
292 return false;
293}
294
295auto internal_m2n_destroy_entity(entt::entity id, float seconds) -> bool
296{
297 seconds = std::max(0.0001f, seconds);
298
299 delta_t secs(seconds);
300 auto dur = std::chrono::duration_cast<seq::duration_t>(secs);
301
302 auto delay = seq::delay(dur);
303 delay.on_end.connect(
304 [id]()
305 {
306 internal_m2n_destroy_entity_immediate(id);
307 });
308
309 seq::start(delay, "script");
310
311 return true;
312}
313
314auto internal_m2n_is_entity_valid(entt::entity id) -> bool
315{
316 auto e = get_entity_from_id(id);
317 bool valid = e.valid();
318 return valid;
319}
320
321auto internal_m2n_find_entity_by_name(const std::string& name) -> entt::entity
322{
323 auto& ctx = engine::context();
324 auto& ec = ctx.get_cached<ecs>();
325 auto& scn = ec.get_scene();
326 auto& registry = *scn.registry;
327
328 auto view = registry.view<tag_component>();
329
330 for(const auto& e : view)
331 {
332 if(registry.get<tag_component>(e).name == name)
333 {
334 return e;
335 }
336 }
337
338 const entt::handle invalid;
339 return invalid.entity();
340}
341
342auto internal_m2n_find_entities_by_name(const std::string& name) -> hpp::small_vector<entt::entity>
343{
344 auto& ctx = engine::context();
345 auto& ec = ctx.get_cached<ecs>();
346 auto& scn = ec.get_scene();
347 auto& registry = *scn.registry;
348
349 auto view = registry.view<tag_component>();
350
351 hpp::small_vector<entt::entity> result;
352 for(const auto& e : view)
353 {
354 if(registry.get<tag_component>(e).name == name)
355 {
356 result.emplace_back(e);
357 }
358 }
359
360 return result;
361}
362
363auto internal_m2n_find_entity_by_tag(const std::string& tag) -> entt::entity
364{
365 auto& ctx = engine::context();
366 auto& ec = ctx.get_cached<ecs>();
367 auto& scn = ec.get_scene();
368 auto& registry = *scn.registry;
369
370 auto view = registry.view<tag_component>();
371
372 for(const auto& e : view)
373 {
374 if(registry.get<tag_component>(e).tag == tag)
375 {
376 return e;
377 }
378 }
379
380 const entt::handle invalid;
381 return invalid.entity();
382}
383
384auto internal_m2n_find_entities_by_tag(const std::string& tag) -> hpp::small_vector<entt::entity>
385{
386 auto& ctx = engine::context();
387 auto& ec = ctx.get_cached<ecs>();
388 auto& scn = ec.get_scene();
389 auto& registry = *scn.registry;
390
391 auto view = registry.view<tag_component>();
392
393 hpp::small_vector<entt::entity> result;
394 for(const auto& e : view)
395 {
396 if(registry.get<tag_component>(e).tag == tag)
397 {
398 result.emplace_back(e);
399 }
400 }
401
402 return result;
403}
404
405struct native_comp_lut
406{
407 auto is_valid() const -> bool
408 {
409 return add_native != nullptr;
410 }
411 std::function<bool(size_t type_hash, entt::handle e)> add_native;
412 std::function<bool(size_t type_hash, entt::handle e)> has_native;
413 std::function<bool(size_t type_hash, entt::handle e)> remove_native;
414
415 static auto get_registry() -> std::unordered_map<size_t, native_comp_lut>&
416 {
417 static std::unordered_map<size_t, native_comp_lut> lut;
418 return lut;
419 }
420
421 static auto get_action_table(size_t type_hash) -> const native_comp_lut&
422 {
423 const auto& registry = get_registry();
424 auto it = registry.find(type_hash);
425 if(it != registry.end())
426 {
427 return it->second;
428 }
429
430 static const native_comp_lut empty;
431 return empty;
432 }
433
434 template<typename T>
435 static auto register_native_component(const std::string& name)
436 {
437 size_t hash = mono::mono_type::get_hash(name);
438 native_comp_lut lut;
439 lut.add_native = [hash](size_t type_hash, entt::handle e)
440 {
441 if(type_hash == hash)
442 {
443 auto& native = e.get_or_emplace<T>();
444 return true;
445 }
446
447 return false;
448 };
449
450 lut.has_native = [hash](size_t type_hash, entt::handle e)
451 {
452 if(type_hash == hash)
453 {
454 return e.all_of<T>();
455 }
456
457 return false;
458 };
459
460 lut.remove_native = [hash](size_t type_hash, entt::handle e)
461 {
462 if(type_hash == hash)
463 {
464 return e.remove<T>() > 0;
465 }
466
467 return false;
468 };
469
470 get_registry()[hash] = lut;
471 }
472};
473
474int register_componetns = []()
475{
476 native_comp_lut::register_native_component<transform_component>("Unravel.Core.TransformComponent");
477 native_comp_lut::register_native_component<id_component>("Unravel.Core.IdComponent");
478 native_comp_lut::register_native_component<model_component>("Unravel.Core.ModelComponent");
479 native_comp_lut::register_native_component<camera_component>("Unravel.Core.CameraComponent");
480 native_comp_lut::register_native_component<light_component>("Unravel.Core.LightComponent");
481 native_comp_lut::register_native_component<reflection_probe_component>("Unravel.Core.ReflectionProbeComponent");
482 native_comp_lut::register_native_component<physics_component>("Unravel.Core.PhysicsComponent");
483 native_comp_lut::register_native_component<animation_component>("Unravel.Core.AnimationComponent");
484 native_comp_lut::register_native_component<audio_listener_component>("Unravel.Core.AudioListenerComponent");
485 native_comp_lut::register_native_component<audio_source_component>("Unravel.Core.AudioSourceComponent");
486 native_comp_lut::register_native_component<bone_component>("Unravel.Core.BoneComponent");
487 native_comp_lut::register_native_component<submesh_component>("Unravel.Core.SubmeshComponent");
488 native_comp_lut::register_native_component<text_component>("Unravel.Core.TextComponent");
489 native_comp_lut::register_native_component<ui_document_component>("Unravel.Core.UIDocumentComponent");
490
491 return 0;
492}();
493
494auto internal_add_native_component(const mono::mono_type& type, entt::handle e, script_component& script_comp)
495 -> mono::mono_object
496{
497 // TODO OPTIMIZE
498
499 const auto& type_hash = type.get_hash();
500 bool add = false;
501
502 const auto& lut = native_comp_lut::get_action_table(type_hash);
503 if(lut.is_valid())
504 {
505 add = lut.add_native(type_hash, e);
506 }
507
508 if(add)
509 {
510 auto comp = script_comp.get_native_component(type);
511
512 if(!comp.scoped)
513 {
514 comp = script_comp.add_native_component(type);
515 }
516 return static_cast<mono::mono_object&>(comp.scoped->object);
517 }
518
519 return {};
520}
521
522auto internal_get_native_component_impl(const mono::mono_type& type,
523 entt::handle e,
524 script_component& script_comp,
525 bool exists) -> mono::mono_object
526{
527 auto comp = script_comp.get_native_component(type);
528 if(exists)
529 {
530 if(!comp.scoped)
531 {
532 comp = script_comp.add_native_component(type);
533 }
534 return static_cast<mono::mono_object&>(comp.scoped->object);
535 }
536
537 if(comp.scoped)
538 {
539 script_comp.remove_native_component(comp.scoped->object);
540 }
541
542 return {};
543}
544
545auto internal_get_native_component(const mono::mono_type& type, entt::handle e, script_component& script_comp)
546 -> mono::mono_object
547{
548 const auto& type_hash = type.get_hash();
549
550 // TODO OPTIMIZE
551 bool native = false;
552 bool has = false;
553
554 const auto& lut = native_comp_lut::get_action_table(type_hash);
555 if(lut.is_valid())
556 {
557 has = lut.has_native(type_hash, e);
558 native = true;
559 }
560
561 if(native)
562 {
563 return internal_get_native_component_impl(type, e, script_comp, has);
564 }
565
566 return {};
567}
568
569auto internal_remove_native_component(const mono::mono_object& obj, entt::handle e, script_component& script_comp)
570 -> bool
571{
572 const auto& type = obj.get_type();
573 const auto& type_hash = type.get_hash();
574
575 // TODO OPTIMIZE
576
577 bool removed = false;
578 const auto& lut = native_comp_lut::get_action_table(type_hash);
579 if(lut.is_valid())
580 {
581 removed = lut.remove_native(type_hash, e);
582 }
583
584 if(removed)
585 {
586 return script_comp.remove_native_component(obj);
587 }
588
589 return false;
590}
591
592auto internal_remove_native_component(const mono::mono_type& type, entt::handle e, script_component& script_comp)
593 -> bool
594{
595 const auto& type_hash = type.get_hash();
596
597 // TODO OPTIMIZE
598
599 bool removed = false;
600 const auto& lut = native_comp_lut::get_action_table(type_hash);
601 if(lut.is_valid())
602 {
603 removed = lut.remove_native(type_hash, e);
604 }
605
606 if(removed)
607 {
608 return script_comp.remove_native_component(type);
609 }
610
611 return false;
612}
613
614auto internal_m2n_add_component(entt::entity id, const mono::mono_type& type) -> mono::mono_object
615{
616 auto e = get_entity_from_id(id);
617 if(!e)
618 {
619 raise_invalid_entity_exception();
620 return {};
621 }
622 auto& script_comp = e.get_or_emplace<script_component>();
623
624 if(auto native_comp = internal_add_native_component(type, e, script_comp))
625 {
626 return native_comp;
627 }
628
629 auto component = script_comp.add_script_component(type);
630 return static_cast<mono::mono_object&>(component.scoped->object);
631}
632
633auto internal_m2n_get_component(entt::entity id, const mono::mono_type& type) -> mono::mono_object
634{
635 auto e = get_entity_from_id(id);
636 if(!e)
637 {
638 raise_invalid_entity_exception();
639 return {};
640 }
641
642 auto& script_comp = e.get_or_emplace<script_component>();
643
644 if(auto native_comp = internal_get_native_component(type, e, script_comp))
645 {
646 return native_comp;
647 }
648
649 auto component = script_comp.get_script_component(type);
650
651 if(component.scoped)
652 {
653 return static_cast<mono::mono_object&>(component.scoped->object);
654 }
655
656 return {};
657}
658
659auto internal_m2n_get_components(entt::entity id, const mono::mono_type& type) -> std::vector<mono::mono_object>
660{
661 auto e = get_entity_from_id(id);
662 if(!e)
663 {
664 raise_invalid_entity_exception();
665 return {};
666 }
667
668 auto& script_comp = e.get_or_emplace<script_component>();
669
670 if(auto native_comp = internal_get_native_component(type, e, script_comp))
671 {
672 return {native_comp};
673 }
674
675 return script_comp.get_script_components(type);
676}
677
678auto internal_m2n_get_component_in_children(entt::entity id, const mono::mono_type& type) -> mono::mono_object
679{
680 if(auto comp = safe_get_component<transform_component>(id))
681 {
682 const auto& children = comp->get_children();
683 for(const auto& child : children)
684 {
685 if(auto result = internal_m2n_get_component(child, type))
686 {
687 return result;
688 }
689 }
690 }
691
692 return {};
693}
694
695auto internal_m2n_get_components_in_children(entt::entity id, const mono::mono_type& type)
696 -> hpp::small_vector<mono::mono_object>
697{
698 hpp::small_vector<mono::mono_object> components;
699 if(auto comp = safe_get_component<transform_component>(id))
700 {
701 const auto& children = comp->get_children();
702 for(const auto& child : children)
703 {
704 auto child_components = internal_m2n_get_components(child, type);
705 std::move(child_components.begin(), child_components.end(), std::back_inserter(components));
706 }
707 }
708 return components;
709}
710
711auto internal_m2n_get_transform_component(entt::entity id, const mono::mono_type& type) -> mono::mono_object
712{
713 auto e = get_entity_from_id(id);
714 if(!e)
715 {
716 raise_invalid_entity_exception();
717 return {};
718 }
719
720 auto& script_comp = e.get_or_emplace<script_component>();
721 return internal_get_native_component_impl(type, e, script_comp, true);
722}
723
724auto internal_m2n_get_name(entt::entity id) -> const std::string&
725{
726 if(auto comp = safe_get_component<tag_component>(id))
727 {
728 return comp->name;
729 }
730
731 static const std::string empty;
732 return empty;
733}
734
735void internal_m2n_set_name(entt::entity id, const std::string& name)
736{
737 if(auto comp = safe_get_component<tag_component>(id))
738 {
739 comp->name = name;
740 }
741}
742
743auto internal_m2n_get_tag(entt::entity id) -> const std::string&
744{
745 if(auto comp = safe_get_component<tag_component>(id))
746 {
747 return comp->tag;
748 }
749
750 static const std::string empty;
751 return empty;
752}
753
754void internal_m2n_set_tag(entt::entity id, const std::string& tag)
755{
756 if(auto comp = safe_get_component<tag_component>(id))
757 {
758 comp->tag = tag;
759 }
760}
761
762auto internal_m2n_get_layers(entt::entity id) -> int
763{
764 if(auto comp = safe_get_component<layer_component>(id))
765 {
766 return comp->layers.mask;
767 }
768
770}
771
772void internal_m2n_set_layers(entt::entity id, int mask)
773{
774 if(auto comp = safe_get_component<layer_component>(id))
775 {
776 comp->layers.mask = mask;
777 }
778}
779
780auto internal_m2n_get_active_global(entt::entity id) -> bool
781{
782 if(auto comp = safe_get_component<transform_component>(id))
783 {
784 return comp->is_active_global();
785 }
786
787 return false;
788}
789
790auto internal_m2n_get_active_local(entt::entity id) -> bool
791{
792 if(auto comp = safe_get_component<transform_component>(id))
793 {
794 return comp->is_active();
795 }
796
797 return false;
798}
799
800void internal_m2n_set_active_local(entt::entity id, bool active)
801{
802 if(auto comp = safe_get_component<transform_component>(id))
803 {
804 comp->set_active(active);
805 }
806}
807
808auto internal_m2n_has_component(entt::entity id, const mono::mono_type& type) -> bool
809{
810 auto comp = internal_m2n_get_component(id, type);
811
812 return comp.valid();
813}
814
815auto internal_m2n_remove_component_instance(entt::entity id, const mono::mono_object& comp) -> bool
816{
817 auto e = get_entity_from_id(id);
818 if(!e)
819 {
820 raise_invalid_entity_exception();
821 return false;
822 }
823 auto& script_comp = e.get_or_emplace<script_component>();
824
825 if(internal_remove_native_component(comp, e, script_comp))
826 {
827 return true;
828 }
829
830 return script_comp.remove_script_component(comp);
831}
832
833auto internal_m2n_remove_component_instance_delay(entt::entity id, const mono::mono_object& comp, float seconds_delay)
834 -> bool
835{
836 delta_t secs(seconds_delay);
837 auto dur = std::chrono::duration_cast<seq::duration_t>(secs);
838
839 auto delay = seq::delay(dur);
840 delay.on_end.connect(
841 [id, comp]()
842 {
843 internal_m2n_remove_component_instance(id, comp);
844 });
845
846 seq::start(delay, "script");
847
848 return true;
849}
850
851auto internal_m2n_remove_component(entt::entity id, const mono::mono_type& type) -> bool
852{
853 auto e = get_entity_from_id(id);
854 if(!e)
855 {
856 raise_invalid_entity_exception();
857 return false;
858 }
859 auto& script_comp = e.get_or_emplace<script_component>();
860
861 if(internal_remove_native_component(type, e, script_comp))
862 {
863 return true;
864 }
865
866 return script_comp.remove_script_component(type);
867}
868
869auto internal_m2n_remove_component_delay(entt::entity id, const mono::mono_type& type, float seconds_delay) -> bool
870{
871 delta_t secs(seconds_delay);
872 auto dur = std::chrono::duration_cast<seq::duration_t>(secs);
873
874 auto delay = seq::delay(dur);
875 delay.on_end.connect(
876 [id, type]()
877 {
878 internal_m2n_remove_component(id, type);
879 });
880
881 seq::start(delay, "script");
882
883 return true;
884}
885
886//-------------------------------------------------------------------------
887/*
888
889 _ ____ _____
890 | | / __ \ / ____|
891 | | | | | | | __
892 | | | | | | | |_ |
893 | |___| |__| | |__| |
894 |______\____/ \_____|
895
896
897*/
898//-------------------------------------------------------------------------
899
900void internal_m2n_log_trace(const std::string& message, const std::string& func, const std::string& file, int line)
901{
902 APPLOG_TRACE_LOC(file.c_str(), line, func.c_str(), message);
903}
904
905void internal_m2n_log_info(const std::string& message, const std::string& func, const std::string& file, int line)
906{
907 APPLOG_INFO_LOC(file.c_str(), line, func.c_str(), message);
908}
909
910void internal_m2n_log_warning(const std::string& message, const std::string& func, const std::string& file, int line)
911{
912 APPLOG_WARNING_LOC(file.c_str(), line, func.c_str(), message);
913}
914
915void internal_m2n_log_error(const std::string& message, const std::string& func, const std::string& file, int line)
916{
917 APPLOG_ERROR_LOC(file.c_str(), line, func.c_str(), message);
918}
919
920//-------------------------------------------------------------------------
921
922void internal_m2n_application_quit()
923{
924 auto delay = seq::delay(1ms);
925 delay.on_end.connect(
926 []()
927 {
928 auto& ctx = engine::context();
929 auto& ev = ctx.get_cached<events>();
930 ev.set_play_mode(ctx, false);
931 });
932
933 seq::start(delay, "script");
934}
935
936void internal_m2n_set_time_scale(float scale)
937{
938 auto& ctx = engine::context();
939 auto& sim = ctx.get_cached<simulation>();
940 sim.set_time_scale(scale);
941}
942
943//-------------------------------------------------------------------------
944/*
945
946 _______ _____ _ _ _____ ______ ____ _____ __ __
947 |__ __| __ \ /\ | \ | |/ ____| ____/ __ \| __ \| \/ |
948 | | | |__) | / \ | \| | (___ | |__ | | | | |__) | \ / |
949 | | | _ / / /\ \ | . ` |\___ \| __|| | | | _ /| |\/| |
950 | | | | \ \ / ____ \| |\ |____) | | | |__| | | \ \| | | |
951 |_| |_| \_\/_/ \_\_| \_|_____/|_| \____/|_| \_\_| |_|
952
953
954*/
955//-------------------------------------------------------------------------
956auto internal_m2n_get_children(entt::entity id) -> hpp::small_vector<entt::entity>
957{
958 if(auto comp = safe_get_component<transform_component>(id))
959 {
960 const auto& children = comp->get_children();
961 hpp::small_vector<entt::entity> children_id;
962 children_id.reserve(children.size());
963 for(const auto& child : children)
964 {
965 children_id.emplace_back(child.entity());
966 }
967 return children_id;
968 }
969
970 return {};
971}
972
973// Helper structure carrying an entity and the count of path segments matched so far.
974struct node_candidate
975{
976 entt::entity entity;
977 size_t matched_index{}; // number of path segments matched so far
978};
979
980auto internal_m2n_get_child(entt::entity id, const std::string& path, bool recursive) -> entt::entity
981{
982 auto root = get_entity_from_id(id);
983 if(!root || path.empty())
984 return entt::null;
985
986 // Tokenize the path once.
987 const auto parts = string_utils::tokenize(path, "/");
988 if(parts.empty())
989 return entt::null;
990
991 // Use a vector as a queue to reduce dynamic allocations.
992 hpp::small_vector<node_candidate> queue;
993 queue.reserve(4); // Reserve a reasonable number based on expected hierarchy size.
994 queue.push_back({root, 0});
995
996 // Process the vector as a queue.
997 for(size_t idx = 0; idx < queue.size(); ++idx)
998 {
999 auto candidate = queue[idx];
1000 bool advanced = false;
1001
1002 // Try matching current candidate.
1003 if(candidate.matched_index < parts.size())
1004 {
1005 if(auto tag_comp = safe_get_component<tag_component>(candidate.entity))
1006 {
1007 if(tag_comp->name == parts[candidate.matched_index])
1008 {
1009 candidate.matched_index++;
1010 advanced = true;
1011 if(candidate.matched_index == parts.size())
1012 {
1013 return candidate.entity;
1014 }
1015 }
1016 }
1017 }
1018
1019 // Determine if we should enqueue children.
1020 // For recursive mode: allow children if no match yet or just advanced.
1021 // For non-recursive mode: allow children only if no match has started.
1022 bool should_enqueue = recursive ? (candidate.matched_index == 0 || advanced) : (candidate.matched_index == 0);
1023
1024 if(should_enqueue)
1025 {
1026 if(auto trans_comp = safe_get_component<transform_component>(candidate.entity))
1027 {
1028 for(const auto& child : trans_comp->get_children())
1029 {
1030 queue.push_back({child.entity(), candidate.matched_index});
1031 }
1032 }
1033 }
1034 }
1035 // No matching entity found.
1036 return entt::null;
1037}
1038
1039auto internal_m2n_get_parent(entt::entity id) -> entt::entity
1040{
1041 if(auto comp = safe_get_component<transform_component>(id))
1042 {
1043 return comp->get_parent().entity();
1044 }
1045
1046 return {};
1047}
1048
1049void internal_m2n_set_parent(entt::entity id, entt::entity new_parent, bool global_stays)
1050{
1051 if(auto comp = safe_get_component<transform_component>(id))
1052 {
1053 auto parent = get_entity_from_id(new_parent);
1054 comp->set_parent(parent, global_stays);
1055 }
1056}
1057
1058auto internal_m2n_get_position_global(entt::entity id) -> math::vec3
1059{
1060 if(auto comp = safe_get_component<transform_component>(id))
1061 {
1062 return comp->get_position_global();
1063 }
1064
1065 return {};
1066}
1067
1068void internal_m2n_set_position_global(entt::entity id, const math::vec3& value)
1069{
1070 if(auto comp = safe_get_component<transform_component>(id))
1071 {
1072 comp->set_position_global(value);
1073 }
1074}
1075
1076void internal_m2n_move_by_global(entt::entity id, const math::vec3& value)
1077{
1078 if(auto comp = safe_get_component<transform_component>(id))
1079 {
1080 comp->move_by_global(value);
1081 }
1082}
1083
1084auto internal_m2n_get_position_local(entt::entity id) -> math::vec3
1085{
1086 if(auto comp = safe_get_component<transform_component>(id))
1087 {
1088 return comp->get_position_local();
1089 }
1090
1091 return {};
1092}
1093
1094void internal_m2n_set_position_local(entt::entity id, const math::vec3& value)
1095{
1096 if(auto comp = safe_get_component<transform_component>(id))
1097 {
1098 comp->set_position_local(value);
1099 }
1100}
1101
1102void internal_m2n_move_by_local(entt::entity id, const math::vec3& value)
1103{
1104 if(auto comp = safe_get_component<transform_component>(id))
1105 {
1106 comp->move_by_local(value);
1107 }
1108}
1109
1110//--------------------------------------------------
1111auto internal_m2n_get_rotation_euler_global(entt::entity id) -> math::vec3
1112{
1113 if(auto comp = safe_get_component<transform_component>(id))
1114 {
1115 return comp->get_rotation_euler_global();
1116 }
1117
1118 return {};
1119}
1120
1121void internal_m2n_rotate_by_euler_global(entt::entity id, const math::vec3& amount)
1122{
1123 if(auto comp = safe_get_component<transform_component>(id))
1124 {
1125 comp->rotate_by_euler_global(amount);
1126 }
1127}
1128
1129void internal_m2n_rotate_axis_global(entt::entity id, float degrees, const math::vec3& axis)
1130{
1131 if(auto comp = safe_get_component<transform_component>(id))
1132 {
1133 comp->rotate_axis_global(degrees, axis);
1134 }
1135}
1136
1137auto internal_m2n_transform_vector_global(entt::entity id, const math::vec3& coord) -> math::vec3
1138{
1139 if(auto comp = safe_get_component<transform_component>(id))
1140 {
1141 const auto& global = comp->get_transform_global();
1142 return global.transform_coord(coord);
1143 }
1144
1145 return {};
1146}
1147
1148auto internal_m2n_inverse_transform_vector_global(entt::entity id, const math::vec3& coord) -> math::vec3
1149{
1150 if(auto comp = safe_get_component<transform_component>(id))
1151 {
1152 const auto& global = comp->get_transform_global();
1153 return global.inverse_transform_coord(coord);
1154 }
1155
1156 return {};
1157}
1158
1159auto internal_m2n_transform_direction_global(entt::entity id, const math::vec3& direction) -> math::vec3
1160{
1161 if(auto comp = safe_get_component<transform_component>(id))
1162 {
1163 const auto& global = comp->get_transform_global();
1164 return global.transform_normal(direction);
1165 }
1166
1167 return {};
1168}
1169
1170auto internal_m2n_inverse_transform_direction_global(entt::entity id, const math::vec3& direction) -> math::vec3
1171{
1172 if(auto comp = safe_get_component<transform_component>(id))
1173 {
1174 const auto& global = comp->get_transform_global();
1175 return global.inverse_transform_normal(direction);
1176 }
1177
1178 return {};
1179}
1180
1181void internal_m2n_look_at(entt::entity id, const math::vec3& point, const math::vec3& up)
1182{
1183 if(auto comp = safe_get_component<transform_component>(id))
1184 {
1185 comp->look_at(point, up);
1186 }
1187}
1188
1189void internal_m2n_set_rotation_euler_global(entt::entity id, const math::vec3& value)
1190{
1191 if(auto comp = safe_get_component<transform_component>(id))
1192 {
1193 comp->set_rotation_euler_global(value);
1194 }
1195}
1196
1197auto internal_m2n_get_rotation_euler_local(entt::entity id) -> math::vec3
1198{
1199 if(auto comp = safe_get_component<transform_component>(id))
1200 {
1201 return comp->get_rotation_euler_local();
1202 }
1203
1204 return {};
1205}
1206
1207void internal_m2n_set_rotation_euler_local(entt::entity id, const math::vec3& value)
1208{
1209 if(auto comp = safe_get_component<transform_component>(id))
1210 {
1211 comp->set_rotation_euler_local(value);
1212 }
1213}
1214
1215void internal_m2n_rotate_by_euler_local(entt::entity id, const math::vec3& amount)
1216{
1217 if(auto comp = safe_get_component<transform_component>(id))
1218 {
1219 comp->rotate_by_euler_local(amount);
1220 }
1221}
1222
1223auto internal_m2n_get_rotation_global(entt::entity id) -> math::quat
1224{
1225 if(auto comp = safe_get_component<transform_component>(id))
1226 {
1227 return comp->get_rotation_global();
1228 }
1229
1230 return {};
1231}
1232
1233void internal_m2n_set_rotation_global(entt::entity id, const math::quat& value)
1234{
1235 if(auto comp = safe_get_component<transform_component>(id))
1236 {
1237 comp->set_rotation_global(value);
1238 }
1239}
1240
1241void internal_m2n_rotate_by_global(entt::entity id, const math::quat& amount)
1242{
1243 if(auto comp = safe_get_component<transform_component>(id))
1244 {
1245 comp->rotate_by_global(amount);
1246 }
1247}
1248
1249auto internal_m2n_get_rotation_local(entt::entity id) -> math::quat
1250{
1251 if(auto comp = safe_get_component<transform_component>(id))
1252 {
1253 return comp->get_rotation_local();
1254 }
1255
1256 return {};
1257}
1258
1259void internal_m2n_set_rotation_local(entt::entity id, const math::quat& value)
1260{
1261 if(auto comp = safe_get_component<transform_component>(id))
1262 {
1263 comp->set_rotation_local(value);
1264 }
1265}
1266
1267void internal_m2n_rotate_by_local(entt::entity id, const math::quat& amount)
1268{
1269 if(auto comp = safe_get_component<transform_component>(id))
1270 {
1271 comp->rotate_by_local(amount);
1272 }
1273}
1274
1275//--------------------------------------------------
1276auto internal_m2n_get_scale_global(entt::entity id) -> math::vec3
1277{
1278 if(auto comp = safe_get_component<transform_component>(id))
1279 {
1280 return comp->get_scale_global();
1281 }
1282
1283 return {};
1284}
1285
1286void internal_m2n_set_scale_global(entt::entity id, const math::vec3& value)
1287{
1288 if(auto comp = safe_get_component<transform_component>(id))
1289 {
1290 comp->set_scale_global(value);
1291 }
1292}
1293
1294void internal_m2n_scale_by_global(entt::entity id, const math::vec3& amount)
1295{
1296 if(auto comp = safe_get_component<transform_component>(id))
1297 {
1298 comp->scale_by_global(amount);
1299 }
1300}
1301
1302auto internal_m2n_get_scale_local(entt::entity id) -> math::vec3
1303{
1304 if(auto comp = safe_get_component<transform_component>(id))
1305 {
1306 return comp->get_scale_local();
1307 }
1308
1309 return {};
1310}
1311
1312void internal_m2n_set_scale_local(entt::entity id, const math::vec3& value)
1313{
1314 if(auto comp = safe_get_component<transform_component>(id))
1315 {
1316 comp->set_scale_local(value);
1317 }
1318}
1319
1320void internal_m2n_scale_by_local(entt::entity id, const math::vec3& amount)
1321{
1322 if(auto comp = safe_get_component<transform_component>(id))
1323 {
1324 comp->scale_by_local(amount);
1325 }
1326}
1327
1328//--------------------------------------------------
1329auto internal_m2n_get_skew_global(entt::entity id) -> math::vec3
1330{
1331 if(auto comp = safe_get_component<transform_component>(id))
1332 {
1333 return comp->get_skew_global();
1334 }
1335
1336 return {};
1337}
1338
1339void internal_m2n_setl_skew_globa(entt::entity id, const math::vec3& value)
1340{
1341 if(auto comp = safe_get_component<transform_component>(id))
1342 {
1343 comp->set_skew_global(value);
1344 }
1345}
1346
1347auto internal_m2n_get_skew_local(entt::entity id) -> math::vec3
1348{
1349 if(auto comp = safe_get_component<transform_component>(id))
1350 {
1351 return comp->get_skew_local();
1352 }
1353
1354 return {};
1355}
1356
1357void internal_m2n_set_skew_local(entt::entity id, const math::vec3& value)
1358{
1359 if(auto comp = safe_get_component<transform_component>(id))
1360 {
1361 comp->set_skew_local(value);
1362 }
1363}
1364
1365//------------------------------
1366
1367void internal_m2n_physics_apply_explosion_force(entt::entity id,
1368 float explosion_force,
1369 const math::vec3& explosion_position,
1370 float explosion_radius,
1371 float upwards_modifier,
1372 force_mode mode)
1373{
1374 if(auto comp = safe_get_component<physics_component>(id))
1375 {
1376 comp->apply_explosion_force(explosion_force, explosion_position, explosion_radius, upwards_modifier, mode);
1377 }
1378}
1379void internal_m2n_physics_apply_force(entt::entity id, const math::vec3& value, force_mode mode)
1380{
1381 if(auto comp = safe_get_component<physics_component>(id))
1382 {
1383 comp->apply_force(value, mode);
1384 }
1385}
1386
1387void internal_m2n_physics_apply_torque(entt::entity id, const math::vec3& value, force_mode mode)
1388{
1389 if(auto comp = safe_get_component<physics_component>(id))
1390 {
1391 comp->apply_torque(value, mode);
1392 }
1393}
1394
1395auto internal_m2n_physics_get_velocity(entt::entity id) -> math::vec3
1396{
1397 if(auto comp = safe_get_component<physics_component>(id))
1398 {
1399 return comp->get_velocity();
1400 }
1401
1402 return {};
1403}
1404
1405void internal_m2n_physics_set_velocity(entt::entity id, const math::vec3& velocity)
1406{
1407 if(auto comp = safe_get_component<physics_component>(id))
1408 {
1409 comp->set_velocity(velocity);
1410 }
1411}
1412
1413auto internal_m2n_physics_get_angular_velocity(entt::entity id) -> math::vec3
1414{
1415 if(auto comp = safe_get_component<physics_component>(id))
1416 {
1417 return comp->get_angular_velocity();
1418 }
1419
1420 return {};
1421}
1422
1423void internal_m2n_physics_set_angular_velocity(entt::entity id, const math::vec3& velocity)
1424{
1425 if(auto comp = safe_get_component<physics_component>(id))
1426 {
1427 comp->set_angular_velocity(velocity);
1428 }
1429}
1430
1431auto internal_m2n_physics_get_include_layers(entt::entity id) -> layer_mask
1432{
1433 if(auto comp = safe_get_component<physics_component>(id))
1434 {
1435 return comp->get_collision_include_mask();
1436 }
1437
1438 return {};
1439}
1440
1441void internal_m2n_physics_set_include_layers(entt::entity id, layer_mask mask)
1442{
1443 if(auto comp = safe_get_component<physics_component>(id))
1444 {
1445 comp->set_collision_include_mask(mask);
1446 }
1447}
1448
1449auto internal_m2n_physics_get_exclude_layers(entt::entity id) -> layer_mask
1450{
1451 if(auto comp = safe_get_component<physics_component>(id))
1452 {
1453 return comp->get_collision_exclude_mask();
1454 }
1455
1456 return {};
1457}
1458
1459void internal_m2n_physics_set_exclude_layers(entt::entity id, layer_mask mask)
1460{
1461 if(auto comp = safe_get_component<physics_component>(id))
1462 {
1463 comp->set_collision_exclude_mask(mask);
1464 }
1465}
1466
1467auto internal_m2n_physics_get_collision_layers(entt::entity id) -> layer_mask
1468{
1469 if(auto comp = safe_get_component<physics_component>(id))
1470 {
1471 return comp->get_collision_mask();
1472 }
1473
1474 return {};
1475}
1476//------------------------------
1477
1478void internal_m2n_animation_blend(entt::entity id, int layer, hpp::uuid guid, float seconds, bool loop, bool phase_sync)
1479{
1480 if(auto comp = safe_get_component<animation_component>(id))
1481 {
1482 auto& ctx = engine::context();
1483 auto& am = ctx.get_cached<asset_manager>();
1484
1485 auto asset = am.get_asset<animation_clip>(guid);
1486 comp->get_player().blend_to(layer, asset, animation_player::seconds_t(seconds), loop, phase_sync);
1487 }
1488}
1489
1490void internal_m2n_animation_play(entt::entity id)
1491{
1492 if(auto comp = safe_get_component<animation_component>(id))
1493 {
1494 comp->get_player().play();
1495 }
1496}
1497
1498void internal_m2n_animation_pause(entt::entity id)
1499{
1500 if(auto comp = safe_get_component<animation_component>(id))
1501 {
1502 comp->get_player().pause();
1503 }
1504}
1505
1506void internal_m2n_animation_resume(entt::entity id)
1507{
1508 if(auto comp = safe_get_component<animation_component>(id))
1509 {
1510 comp->get_player().resume();
1511 }
1512}
1513
1514void internal_m2n_animation_stop(entt::entity id)
1515{
1516 if(auto comp = safe_get_component<animation_component>(id))
1517 {
1518 comp->get_player().stop();
1519 }
1520}
1521
1522void internal_m2n_animation_set_speed(entt::entity id, float speed)
1523{
1524 if(auto comp = safe_get_component<animation_component>(id))
1525 {
1526 comp->set_speed(speed);
1527 }
1528}
1529
1530auto internal_m2n_animation_get_speed(entt::entity id) -> float
1531{
1532 if(auto comp = safe_get_component<animation_component>(id))
1533 {
1534 return comp->get_speed();
1535 }
1536 return 1.0f;
1537}
1538
1539//------------------------------
1540auto internal_m2n_camera_screen_point_to_ray(entt::entity id,
1541 const math::vec2& origin,
1542 mono::managed_interface::ray* managed_ray) -> bool
1543{
1544 if(auto comp = safe_get_component<camera_component>(id))
1545 {
1546 math::vec3 ray_origin{};
1547 math::vec3 ray_dir{};
1548 bool result = comp->get_camera().viewport_to_ray(origin, ray_origin, ray_dir);
1549 if(result)
1550 {
1551 using converter = mono::managed_interface::converter;
1552 managed_ray->origin = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_origin);
1553 managed_ray->direction = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_dir);
1554 }
1555 return result;
1556 }
1557
1558 return false;
1559}
1560//------------------------------
1561auto internal_m2n_model_get_enabled(entt::entity id) -> bool
1562{
1563 if(auto comp = safe_get_component<model_component>(id))
1564 {
1565 return comp->is_enabled();
1566 }
1567
1568 return false;
1569}
1570
1571void internal_m2n_model_set_enabled(entt::entity id, bool enabled)
1572{
1573 if(auto comp = safe_get_component<model_component>(id))
1574 {
1575 comp->set_enabled(enabled);
1576 }
1577}
1578
1579auto internal_m2n_model_get_shared_material(entt::entity id, uint32_t index) -> hpp::uuid
1580{
1581 if(auto comp = safe_get_component<model_component>(id))
1582 {
1583 return comp->get_model().get_material(index).uid();
1584 }
1585
1586 return {};
1587}
1588
1589auto internal_m2n_model_get_shared_material_count(entt::entity id) -> int
1590{
1591 if(auto comp = safe_get_component<model_component>(id))
1592 {
1593 return comp->get_model().get_materials().size();
1594 }
1595
1596 return {};
1597}
1598
1599auto internal_m2n_model_get_material_instance(entt::entity id, uint32_t index)
1601{
1602 if(auto comp = safe_get_component<model_component>(id))
1603 {
1604 auto instance = comp->get_model().get_material_instance(index);
1605 return get_material_properties(instance);
1606 }
1607
1608 return {};
1609}
1610
1611void internal_m2n_model_set_shared_material(entt::entity id, const hpp::uuid& uid, uint32_t index)
1612{
1613 if(auto comp = safe_get_component<model_component>(id))
1614 {
1615 auto& ctx = engine::context();
1616 auto& am = ctx.get_cached<asset_manager>();
1617 auto asset = am.get_asset<material>(uid);
1618
1619 auto model = comp->get_model();
1620 model.set_material(asset, index);
1621 comp->set_model(model);
1622 }
1623}
1624
1625void internal_m2n_model_set_material_instance(entt::entity id,
1627 uint32_t index)
1628{
1629 using converter = mono::managed_interface::converter;
1630
1631 if(auto comp = safe_get_component<model_component>(id))
1632 {
1633 auto model = comp->get_model();
1634
1635 if(props.valid)
1636 {
1637 auto material = model.get_or_emplace_material_instance(index);
1638 set_material_properties(material, props);
1639 model.set_material_instance(material, index);
1640 }
1641 else
1642 {
1643 model.set_material_instance(nullptr, index);
1644 }
1645 comp->set_model(model);
1646 }
1647}
1648
1649auto internal_m2n_model_get_material_instance_count(entt::entity id) -> int
1650{
1651 if(auto comp = safe_get_component<model_component>(id))
1652 {
1653 return comp->get_model().get_material_instances().size();
1654 }
1655
1656 return {};
1657}
1658
1659//------------------------------
1660auto internal_m2n_text_get_text(entt::entity id) -> const std::string&
1661{
1662 if(auto comp = safe_get_component<text_component>(id))
1663 {
1664 return comp->get_text();
1665 }
1666
1667 static const std::string empty;
1668 return empty;
1669}
1670
1671void internal_m2n_text_set_text(entt::entity id, const std::string& text)
1672{
1673 if(auto comp = safe_get_component<text_component>(id))
1674 {
1675 comp->set_text(text);
1676 }
1677}
1678
1679auto internal_m2n_text_get_buffer_type(entt::entity id) -> text_component::buffer_type
1680{
1681 if(auto comp = safe_get_component<text_component>(id))
1682 {
1683 return comp->get_buffer_type();
1684 }
1685
1687}
1688
1689void internal_m2n_text_set_buffer_type(entt::entity id, text_component::buffer_type type)
1690{
1691 if(auto comp = safe_get_component<text_component>(id))
1692 {
1693 comp->set_buffer_type(type);
1694 }
1695}
1696
1697auto internal_m2n_text_get_overflow_type(entt::entity id) -> text_component::overflow_type
1698{
1699 if(auto comp = safe_get_component<text_component>(id))
1700 {
1701 return comp->get_overflow_type();
1702 }
1703
1705}
1706
1707void internal_m2n_text_set_overflow_type(entt::entity id, text_component::overflow_type type)
1708{
1709 if(auto comp = safe_get_component<text_component>(id))
1710 {
1711 comp->set_overflow_type(type);
1712 }
1713}
1714
1715auto internal_m2n_text_get_font(entt::entity id) -> hpp::uuid
1716{
1717 if(auto comp = safe_get_component<text_component>(id))
1718 {
1719 return comp->get_font().uid();
1720 }
1721
1722 return hpp::uuid{};
1723}
1724
1725void internal_m2n_text_set_font(entt::entity id, hpp::uuid uid)
1726{
1727 if(auto comp = safe_get_component<text_component>(id))
1728 {
1729 auto& ctx = engine::context();
1730 auto& am = ctx.get_cached<asset_manager>();
1731
1732 auto asset = am.get_asset<font>(uid);
1733 comp->set_font(asset);
1734 }
1735}
1736
1737auto internal_m2n_text_get_font_size(entt::entity id) -> uint32_t
1738{
1739 if(auto comp = safe_get_component<text_component>(id))
1740 {
1741 return comp->get_font_size();
1742 }
1743
1744 return 0;
1745}
1746
1747void internal_m2n_text_set_font_size(entt::entity id, uint32_t font_size)
1748{
1749 if(auto comp = safe_get_component<text_component>(id))
1750 {
1751 comp->set_font_size(font_size);
1752 }
1753}
1754
1755auto internal_m2n_text_get_render_font_size(entt::entity id) -> uint32_t
1756{
1757 if(auto comp = safe_get_component<text_component>(id))
1758 {
1759 return comp->get_render_font_size();
1760 }
1761
1762 return 0;
1763}
1764
1765auto internal_m2n_text_get_auto_size(entt::entity id) -> bool
1766{
1767 if(auto comp = safe_get_component<text_component>(id))
1768 {
1769 return comp->get_auto_size();
1770 }
1771
1772 return false;
1773}
1774
1775void internal_m2n_text_set_auto_size(entt::entity id, bool auto_size)
1776{
1777 if(auto comp = safe_get_component<text_component>(id))
1778 {
1779 comp->set_auto_size(auto_size);
1780 }
1781}
1782auto internal_m2n_text_get_auto_size_range(entt::entity id) -> urange32_t
1783{
1784 if(auto comp = safe_get_component<text_component>(id))
1785 {
1786 return comp->get_auto_size_range();
1787 }
1788
1789 return {};
1790}
1791
1792void internal_m2n_text_set_auto_size_range(entt::entity id, urange32_t range)
1793{
1794 if(auto comp = safe_get_component<text_component>(id))
1795 {
1796 comp->set_auto_size_range(range);
1797 }
1798}
1799
1800auto internal_m2n_text_get_area(entt::entity id) -> math::vec2
1801{
1802 if(auto comp = safe_get_component<text_component>(id))
1803 {
1804 auto area = comp->get_area();
1805 return {area.width, area.height};
1806 }
1807
1808 return {};
1809}
1810
1811void internal_m2n_text_set_area(entt::entity id, math::vec2 area)
1812{
1813 if(auto comp = safe_get_component<text_component>(id))
1814 {
1815 comp->set_area({area.x, area.y});
1816 }
1817}
1818
1819auto internal_m2n_text_get_render_area(entt::entity id) -> math::vec2
1820{
1821 if(auto comp = safe_get_component<text_component>(id))
1822 {
1823 auto area = comp->get_render_area();
1824 return {area.width, area.height};
1825 }
1826
1827 return {};
1828}
1829
1830auto internal_m2n_text_get_is_rich_text(entt::entity id) -> bool
1831{
1832 if(auto comp = safe_get_component<text_component>(id))
1833 {
1834 return comp->get_is_rich_text();
1835 }
1836
1837 return false;
1838}
1839
1840void internal_m2n_text_set_is_rich_text(entt::entity id, bool rich)
1841{
1842 if(auto comp = safe_get_component<text_component>(id))
1843 {
1844 comp->set_is_rich_text(rich);
1845 }
1846}
1847
1848auto internal_m2n_text_get_alignment(entt::entity id) -> uint32_t
1849{
1850 if(auto comp = safe_get_component<text_component>(id))
1851 {
1852 return comp->get_alignment().flags;
1853 }
1854
1855 return alignment{}.flags;
1856}
1857
1858void internal_m2n_text_set_alignment(entt::entity id, uint32_t alignment_flags)
1859{
1860 if(auto comp = safe_get_component<text_component>(id))
1861 {
1862 comp->set_alignment({alignment_flags});
1863 }
1864}
1865
1866auto internal_m2n_text_get_bounds(entt::entity id) -> math::bbox
1867{
1868 if(auto comp = safe_get_component<text_component>(id))
1869 {
1870 return comp->get_bounds();
1871 }
1872
1873 return math::bbox::empty;
1874}
1875
1876auto internal_m2n_text_get_render_bounds(entt::entity id) -> math::bbox
1877{
1878 if(auto comp = safe_get_component<text_component>(id))
1879 {
1880 return comp->get_render_bounds();
1881 }
1882
1883 return math::bbox::empty;
1884}
1885//------------------------------
1886
1887void internal_m2n_light_set_color(entt::entity id, const math::color& color)
1888{
1889 if(auto comp = safe_get_component<light_component>(id))
1890 {
1891 auto l = comp->get_light();
1892 l.color = color;
1893 comp->set_light(l);
1894 }
1895}
1896
1897auto internal_m2n_light_get_color(entt::entity id) -> math::color
1898{
1899 if(auto comp = safe_get_component<light_component>(id))
1900 {
1901 return comp->get_light().color;
1902 }
1903
1904 return math::color::white();
1905}
1906//------------------------------
1907
1908auto internal_m2n_from_euler_rad(const math::vec3& euler) -> math::quat
1909{
1910 return {euler};
1911}
1912
1913auto internal_m2n_to_euler_rad(const math::quat& euler) -> math::vec3
1914{
1915 return math::eulerAngles(euler);
1916}
1917
1918auto internal_m2n_angle_axis(float angle, const math::vec3& axis) -> math::quat
1919{
1920 return math::angleAxis(angle, axis);
1921}
1922
1923auto internal_m2n_look_rotation(const math::vec3& forward, const math::vec3& up) -> math::quat
1924{
1925 return math::look_rotation(forward, up);
1926}
1927
1928auto internal_m2n_from_to_rotation(const math::vec3& from, const math::vec3& to) -> math::quat
1929{
1930 return math::from_to_rotation(from, to);
1931}
1932
1933auto internal_m2n_get_asset_by_uuid(const hpp::uuid& uid, const mono::mono_type& type) -> hpp::uuid
1934{
1935 if(auto asset = get_mono_asset(type.get_hash()))
1936 {
1937 return asset->get_asset_uuid(uid);
1938 }
1939
1940 return {};
1941}
1942
1943auto internal_m2n_get_asset_by_key(const std::string& key, const mono::mono_type& type) -> hpp::uuid
1944{
1945 if(auto asset = get_mono_asset(type.get_hash()))
1946 {
1947 return asset->get_asset_uuid(key);
1948 }
1949
1950 return {};
1951}
1952
1953auto internal_m2n_get_material_properties(const hpp::uuid& uid) -> mono::managed_interface::material_properties
1954{
1955 using converter = mono::managed_interface::converter;
1956
1957 auto& ctx = engine::context();
1958 auto& am = ctx.get_cached<asset_manager>();
1959
1961 auto asset = am.get_asset<material>(uid);
1962 if(!asset)
1963 {
1964 return props;
1965 }
1966 auto material = asset.get();
1967
1968 return get_material_properties(material);
1969}
1970
1971auto internal_m2n_audio_clip_get_length(const hpp::uuid& uid) -> float
1972{
1973 auto& ctx = engine::context();
1974 auto& am = ctx.get_cached<asset_manager>();
1975
1976 auto asset = am.get_asset<audio_clip>(uid);
1977
1978 if(asset.is_valid())
1979 {
1980 if(auto clip = asset.get())
1981 {
1982 float secs = clip->get_info().duration.count();
1983 return secs;
1984 }
1985 }
1986
1987 return 0.0f;
1988}
1989auto m2n_test_uuid(const hpp::uuid& uid) -> hpp::uuid
1990{
1991 APPLOG_INFO("{}:: From C# {}", __func__, hpp::to_string(uid));
1992
1993 auto newuid = generate_uuid();
1994 APPLOG_INFO("{}:: New C++ {}", __func__, hpp::to_string(newuid));
1995
1996 return newuid;
1997}
1998
1999void internal_m2n_gizmos_add_sphere(const math::color& color, const math::vec3& position, float radius)
2000{
2001 auto& ctx = engine::context();
2002 auto& path = ctx.get_cached<rendering_system>();
2003 path.add_debugdraw_call(
2004 [color, position, radius](gfx::dd_raii& dd)
2005 {
2007 dd.encoder.setColor(color);
2008 dd.encoder.setWireframe(true);
2009
2010 bx::Sphere sphere;
2011 sphere.center.x = position.x;
2012 sphere.center.y = position.y;
2013 sphere.center.z = position.z;
2014 sphere.radius = radius;
2015 dd.encoder.draw(sphere);
2016 });
2017}
2018
2019void internal_m2n_gizmos_add_ray(const math::color& color,
2020 const math::vec3& position,
2021 const math::vec3& direction,
2022 float max_distance)
2023{
2024 auto& ctx = engine::context();
2025 auto& path = ctx.get_cached<rendering_system>();
2026 path.add_debugdraw_call(
2027 [color, position, direction, max_distance](gfx::dd_raii& dd)
2028 {
2030 dd.encoder.setColor(color);
2031 dd.encoder.setWireframe(true);
2032
2033 bx::Ray ray;
2034 ray.pos.x = position.x;
2035 ray.pos.y = position.y;
2036 ray.pos.z = position.z;
2037
2038 ray.dir.x = direction.x;
2039 ray.dir.y = direction.y;
2040 ray.dir.z = direction.z;
2041
2042 dd.encoder.push();
2043 dd.encoder.moveTo(ray.pos);
2044 dd.encoder.lineTo(bx::mul(ray.dir, max_distance));
2045 dd.encoder.pop();
2046 });
2047}
2048
2049auto internal_m2n_layers_layer_to_name(int layer) -> const std::string&
2050{
2051 auto& ctx = engine::context();
2052 auto& csettings = ctx.get<settings>();
2053
2054 if(layer >= csettings.layer.layers.size())
2055 {
2056 mono::raise_exception("System", "Exception", fmt::format("Layer index {} is out of bounds.", layer));
2057
2058 static const std::string empty;
2059 return empty;
2060 }
2061 return csettings.layer.layers[layer];
2062}
2063
2064auto internal_m2n_layers_name_to_layer(const std::string& name) -> int
2065{
2066 auto& ctx = engine::context();
2067 auto& csettings = ctx.get<settings>();
2068
2069 auto it = std::find(csettings.layer.layers.begin(), csettings.layer.layers.end(), name);
2070 if(it != csettings.layer.layers.end())
2071 {
2072 return static_cast<int>(std::distance(csettings.layer.layers.begin(), it));
2073 }
2074
2075 return -1;
2076}
2077
2078auto internal_m2n_input_get_analog_value(const std::string& name) -> float
2079{
2080 auto& ctx = engine::context();
2081 auto& input = ctx.get_cached<input_system>();
2082 return input.get_analog_value(name);
2083}
2084
2085auto internal_m2n_input_get_digital_value(const std::string& name) -> bool
2086{
2087 auto& ctx = engine::context();
2088 auto& input = ctx.get_cached<input_system>();
2089 return input.get_digital_value(name);
2090}
2091
2092auto internal_m2n_input_is_pressed(const std::string& name) -> bool
2093{
2094 auto& ctx = engine::context();
2095 auto& input = ctx.get_cached<input_system>();
2096 return input.is_pressed(name);
2097}
2098
2099auto internal_m2n_input_is_released(const std::string& name) -> bool
2100{
2101 auto& ctx = engine::context();
2102 auto& input = ctx.get_cached<input_system>();
2103 return input.is_released(name);
2104}
2105
2106auto internal_m2n_input_is_down(const std::string& name) -> bool
2107{
2108 auto& ctx = engine::context();
2109 auto& input = ctx.get_cached<input_system>();
2110 return input.is_down(name);
2111}
2112
2113auto internal_m2n_input_is_key_pressed(input::key_code code) -> bool
2114{
2115 auto& ctx = engine::context();
2116 auto& input = ctx.get_cached<input_system>();
2117 return input.manager.get_keyboard().is_pressed(code);
2118}
2119
2120auto internal_m2n_input_is_key_released(input::key_code code) -> bool
2121{
2122 auto& ctx = engine::context();
2123 auto& input = ctx.get_cached<input_system>();
2124 return input.manager.get_keyboard().is_released(code);
2125}
2126
2127auto internal_m2n_input_is_key_down(input::key_code code) -> bool
2128{
2129 auto& ctx = engine::context();
2130 auto& input = ctx.get_cached<input_system>();
2131 return input.manager.get_keyboard().is_down(code);
2132}
2133
2134auto internal_m2n_input_is_mouse_button_pressed(int32_t button) -> bool
2135{
2136 auto& ctx = engine::context();
2137 auto& input = ctx.get_cached<input_system>();
2138 return input.manager.get_mouse().is_pressed(button);
2139}
2140
2141auto internal_m2n_input_is_mouse_button_released(int32_t button) -> bool
2142{
2143 auto& ctx = engine::context();
2144 auto& input = ctx.get_cached<input_system>();
2145 return input.manager.get_mouse().is_released(button);
2146}
2147
2148auto internal_m2n_input_is_mouse_button_down(int32_t button) -> bool
2149{
2150 auto& ctx = engine::context();
2151 auto& input = ctx.get_cached<input_system>();
2152 return input.manager.get_mouse().is_down(button);
2153}
2154
2155auto internal_m2n_input_get_mouse_position() -> math::vec2
2156{
2157 auto& ctx = engine::context();
2158 auto& input = ctx.get_cached<input_system>();
2159 auto coord = input.manager.get_mouse().get_position();
2160 return {coord.x, coord.y};
2161}
2162
2163//-------------------------------------------------
2164
2165auto internal_m2n_physics_ray_cast(mono::managed_interface::raycast_hit* hit,
2166 const math::vec3& origin,
2167 const math::vec3& direction,
2168 float max_distance,
2169 int layer_mask,
2170 bool query_sensors) -> bool
2171{
2172 auto& ctx = engine::context();
2173 auto& physics = ctx.get_cached<physics_system>();
2174
2175 auto ray_hit = physics.ray_cast(origin, direction, max_distance, layer_mask, query_sensors);
2176
2177 using converter = mono::managed_interface::converter;
2178
2179 if(ray_hit)
2180 {
2181 hit->entity = ray_hit->entity;
2182 hit->point = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit->point);
2183 hit->normal = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit->normal);
2184 hit->distance = ray_hit->distance;
2185 }
2186
2187 return ray_hit.has_value();
2188}
2189
2190auto internal_m2n_physics_ray_cast_all(const math::vec3& origin,
2191 const math::vec3& direction,
2192 float max_distance,
2193 int layer_mask,
2194 bool query_sensors) -> hpp::small_vector<mono::managed_interface::raycast_hit>
2195{
2196 auto& ctx = engine::context();
2197 auto& physics = ctx.get_cached<physics_system>();
2198
2199 auto ray_hits = physics.ray_cast_all(origin, direction, max_distance, layer_mask, query_sensors);
2200
2201 hpp::small_vector<mono::managed_interface::raycast_hit> hits;
2202
2203 using converter = mono::managed_interface::converter;
2204 for(const auto& ray_hit : ray_hits)
2205 {
2206 auto& hit = hits.emplace_back();
2207 hit.entity = ray_hit.entity;
2208 hit.point = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit.point);
2209 hit.normal = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit.normal);
2210 hit.distance = ray_hit.distance;
2211 }
2212
2213 return hits;
2214}
2215
2216auto internal_m2n_physics_sphere_cast(mono::managed_interface::raycast_hit* hit,
2217 const math::vec3& origin,
2218 const math::vec3& direction,
2219 float radius,
2220 float max_distance,
2221 int layer_mask,
2222 bool query_sensors) -> bool
2223{
2224 auto& ctx = engine::context();
2225 auto& physics = ctx.get_cached<physics_system>();
2226
2227 auto ray_hit = physics.sphere_cast(origin, direction, radius, max_distance, layer_mask, query_sensors);
2228
2229 using converter = mono::managed_interface::converter;
2230
2231 if(ray_hit)
2232 {
2233 hit->entity = ray_hit->entity;
2234 hit->point = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit->point);
2235 hit->normal = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit->normal);
2236 hit->distance = ray_hit->distance;
2237 }
2238
2239 return ray_hit.has_value();
2240}
2241
2242auto internal_m2n_physics_sphere_cast_all(const math::vec3& origin,
2243 const math::vec3& direction,
2244 float radius,
2245 float max_distance,
2246 int layer_mask,
2247 bool query_sensors) -> hpp::small_vector<mono::managed_interface::raycast_hit>
2248{
2249 auto& ctx = engine::context();
2250 auto& physics = ctx.get_cached<physics_system>();
2251
2252 auto ray_hits = physics.sphere_cast_all(origin, direction, radius, max_distance, layer_mask, query_sensors);
2253
2254 hpp::small_vector<mono::managed_interface::raycast_hit> hits;
2255
2256 using converter = mono::managed_interface::converter;
2257 for(const auto& ray_hit : ray_hits)
2258 {
2259 auto& hit = hits.emplace_back();
2260 hit.entity = ray_hit.entity;
2261 hit.point = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit.point);
2262 hit.normal = converter::convert<math::vec3, mono::managed_interface::vector3>(ray_hit.normal);
2263 hit.distance = ray_hit.distance;
2264 }
2265
2266 return hits;
2267}
2268
2269auto internal_m2n_physics_sphere_overlap(const math::vec3& origin, float radius, int layer_mask, bool query_sensors)
2271{
2272 auto& ctx = engine::context();
2273 auto& physics = ctx.get_cached<physics_system>();
2274
2275 auto hits = physics.sphere_overlap(origin, radius, layer_mask, query_sensors);
2276
2277 return hits;
2278}
2279
2280//-------------------------------------------------
2281
2282auto internal_m2n_audio_source_get_loop(entt::entity id) -> bool
2283{
2284 if(auto comp = safe_get_component<audio_source_component>(id))
2285 {
2286 return comp->is_looping();
2287 }
2288
2289 return {};
2290}
2291
2292//-------------------------------------------------
2293
2294void internal_m2n_utils_set_ik_posiiton_ccd(entt::entity id,
2295 const math::vec3& target,
2296 int num_bones_in_chain,
2297 float threshold,
2298 int max_iterations)
2299{
2300 auto e = get_entity_from_id(id);
2301
2302 ik_set_position_ccd(e, target, num_bones_in_chain, threshold, max_iterations);
2303}
2304
2305void internal_m2n_utils_set_ik_posiiton_fabrik(entt::entity id,
2306 const math::vec3& target,
2307 int num_bones_in_chain,
2308 float threshold,
2309 int max_iterations)
2310{
2311 auto e = get_entity_from_id(id);
2312
2313 ik_set_position_fabrik(e, target, num_bones_in_chain, threshold, max_iterations);
2314}
2315
2316void internal_m2n_utils_set_ik_posiiton_two_bone(entt::entity id,
2317 const math::vec3& target,
2318 const math::vec3& forward,
2319 float weight,
2320 float soften,
2321 int max_iterations)
2322{
2323 auto e = get_entity_from_id(id);
2324
2325 ik_set_position_two_bone(e, target, forward, weight, soften, max_iterations);
2326}
2327
2328void internal_m2n_utils_set_ik_look_at_posiiton(entt::entity id, const math::vec3& target, float weight)
2329{
2330 auto e = get_entity_from_id(id);
2331
2332 ik_look_at_position(e, target, weight);
2333}
2334
2335void internal_m2n_audio_source_set_loop(entt::entity id, bool loop)
2336{
2337 if(auto comp = safe_get_component<audio_source_component>(id))
2338 {
2339 comp->set_loop(loop);
2340 }
2341}
2342
2343auto internal_m2n_audio_source_get_volume(entt::entity id) -> float
2344{
2345 if(auto comp = safe_get_component<audio_source_component>(id))
2346 {
2347 return comp->get_volume();
2348 }
2349
2350 return {};
2351}
2352
2353void internal_m2n_audio_source_set_volume(entt::entity id, float volume)
2354{
2355 if(auto comp = safe_get_component<audio_source_component>(id))
2356 {
2357 comp->set_volume(volume);
2358 }
2359}
2360
2361auto internal_m2n_audio_source_get_pitch(entt::entity id) -> float
2362{
2363 if(auto comp = safe_get_component<audio_source_component>(id))
2364 {
2365 return comp->get_pitch();
2366 }
2367
2368 return {};
2369}
2370
2371void internal_m2n_audio_source_set_pitch(entt::entity id, float pitch)
2372{
2373 if(auto comp = safe_get_component<audio_source_component>(id))
2374 {
2375 comp->set_pitch(pitch);
2376 }
2377}
2378
2379auto internal_m2n_audio_source_get_volume_rolloff(entt::entity id) -> float
2380{
2381 if(auto comp = safe_get_component<audio_source_component>(id))
2382 {
2383 return comp->get_volume_rolloff();
2384 }
2385
2386 return {};
2387}
2388
2389void internal_m2n_audio_source_set_volume_rolloff(entt::entity id, float rolloff)
2390{
2391 if(auto comp = safe_get_component<audio_source_component>(id))
2392 {
2393 comp->set_volume_rolloff(rolloff);
2394 }
2395}
2396
2397auto internal_m2n_audio_source_get_min_distance(entt::entity id) -> float
2398{
2399 if(auto comp = safe_get_component<audio_source_component>(id))
2400 {
2401 return comp->get_range().min;
2402 }
2403
2404 return {};
2405}
2406
2407void internal_m2n_audio_source_set_min_distance(entt::entity id, float distance)
2408{
2409 if(auto comp = safe_get_component<audio_source_component>(id))
2410 {
2411 auto range = comp->get_range();
2412 range.min = distance;
2413 comp->set_range(range);
2414 }
2415}
2416
2417auto internal_m2n_audio_source_get_max_distance(entt::entity id) -> float
2418{
2419 if(auto comp = safe_get_component<audio_source_component>(id))
2420 {
2421 return comp->get_range().max;
2422 }
2423
2424 return {};
2425}
2426
2427void internal_m2n_audio_source_set_max_distance(entt::entity id, float distance)
2428{
2429 if(auto comp = safe_get_component<audio_source_component>(id))
2430 {
2431 auto range = comp->get_range();
2432 range.max = distance;
2433 comp->set_range(range);
2434 }
2435}
2436
2437auto internal_m2n_audio_source_get_mute(entt::entity id) -> bool
2438{
2439 if(auto comp = safe_get_component<audio_source_component>(id))
2440 {
2441 return comp->is_muted();
2442 }
2443
2444 return {};
2445}
2446
2447void internal_m2n_audio_source_set_mute(entt::entity id, bool mute)
2448{
2449 if(auto comp = safe_get_component<audio_source_component>(id))
2450 {
2451 comp->set_mute(mute);
2452 }
2453}
2454
2455auto internal_m2n_audio_source_get_time(entt::entity id) -> float
2456{
2457 if(auto comp = safe_get_component<audio_source_component>(id))
2458 {
2459 return float(comp->get_playback_position().count());
2460 }
2461
2462 return {};
2463}
2464
2465void internal_m2n_audio_source_set_time(entt::entity id, float seconds)
2466{
2467 if(auto comp = safe_get_component<audio_source_component>(id))
2468 {
2469 comp->set_playback_position(audio::duration_t(seconds));
2470 }
2471}
2472
2473auto internal_m2n_audio_source_is_playing(entt::entity id) -> bool
2474{
2475 if(auto comp = safe_get_component<audio_source_component>(id))
2476 {
2477 return comp->is_playing();
2478 }
2479
2480 return {};
2481}
2482
2483auto internal_m2n_audio_source_is_paused(entt::entity id) -> bool
2484{
2485 if(auto comp = safe_get_component<audio_source_component>(id))
2486 {
2487 return comp->is_paused();
2488 }
2489
2490 return {};
2491}
2492
2493void internal_m2n_audio_source_play(entt::entity id)
2494{
2495 if(auto comp = safe_get_component<audio_source_component>(id))
2496 {
2497 comp->play();
2498 }
2499}
2500
2501void internal_m2n_audio_source_stop(entt::entity id)
2502{
2503 if(auto comp = safe_get_component<audio_source_component>(id))
2504 {
2505 comp->stop();
2506 }
2507}
2508
2509void internal_m2n_audio_source_pause(entt::entity id)
2510{
2511 if(auto comp = safe_get_component<audio_source_component>(id))
2512 {
2513 comp->pause();
2514 }
2515}
2516
2517void internal_m2n_audio_source_resume(entt::entity id)
2518{
2519 if(auto comp = safe_get_component<audio_source_component>(id))
2520 {
2521 comp->resume();
2522 }
2523}
2524
2525auto internal_m2n_audio_source_get_audio_clip(entt::entity id) -> hpp::uuid
2526{
2527 if(auto comp = safe_get_component<audio_source_component>(id))
2528 {
2529 return comp->get_clip().uid();
2530 }
2531
2532 return {};
2533}
2534
2535void internal_m2n_audio_source_set_audio_clip(entt::entity id, hpp::uuid uid)
2536{
2537 if(auto comp = safe_get_component<audio_source_component>(id))
2538 {
2539 auto& ctx = engine::context();
2540 auto& am = ctx.get_cached<asset_manager>();
2541
2542 auto asset = am.get_asset<audio_clip>(uid);
2543 comp->set_clip(asset);
2544 }
2545}
2546
2547//--------------------------------------------------
2548
2549//-------------------------------------------------------------------------
2550/*
2551
2552 _ _ _____ _____ _____ _ _ __ __ ______ _ _ _______
2553 | | | |_ _| | __ \ /\ / ____| | | | \/ | ____| \ | |__ __|
2554 | | | | | | | | | | / \ | | | | | | \ / | |__ | \| | | |
2555 | | | | | | | | | |/ /\ \ | | | | | | |\/| | __| | . ` | | |
2556 | |__| |_| |_ | |__| / ____ \| |____| |__| | | | | |____| |\ | | |
2557 \____/|_____| |_____/_/ \_\\_____|\____/|_| |_|______|_| \_| |_|
2558
2559
2560*/
2561//-------------------------------------------------------------------------
2562
2563auto internal_m2n_ui_document_get_asset(entt::entity id) -> hpp::uuid
2564{
2565 if(auto comp = safe_get_component<ui_document_component>(id))
2566 {
2567 return comp->asset.uid();
2568 }
2569
2570 return {};
2571}
2572
2573void internal_m2n_ui_document_set_asset(entt::entity id, const hpp::uuid& uid)
2574{
2575 if(auto comp = safe_get_component<ui_document_component>(id))
2576 {
2577 auto& ctx = engine::context();
2578 auto& am = ctx.get_cached<asset_manager>();
2579
2580 auto asset = am.get_asset<ui_tree>(uid);
2581 comp->asset = asset;
2582 }
2583}
2584
2585auto internal_m2n_ui_document_is_loaded(entt::entity id) -> bool
2586{
2587 if(auto comp = safe_get_component<ui_document_component>(id))
2588 {
2589 return comp->is_loaded();
2590 }
2591
2592 return false;
2593}
2594
2595auto internal_m2n_ui_document_is_enabled(entt::entity id) -> bool
2596{
2597 if(auto comp = safe_get_component<ui_document_component>(id))
2598 {
2599 return comp->is_enabled();
2600 }
2601
2602 return false;
2603}
2604
2605void internal_m2n_ui_document_set_enabled(entt::entity id, bool enabled)
2606{
2607 if(auto comp = safe_get_component<ui_document_component>(id))
2608 {
2609 comp->set_enabled(enabled);
2610 }
2611}
2612void internal_m2n_ui_document_close(entt::entity id)
2613{
2614 if(auto comp = safe_get_component<ui_document_component>(id))
2615 {
2616 if(comp->document)
2617 {
2618 comp->document->Close();
2619 comp->document = nullptr;
2620 }
2621 }
2622}
2623
2624auto internal_m2n_ui_document_get_title(entt::entity id) -> const std::string&
2625{
2626 if(auto comp = safe_get_component<ui_document_component>(id))
2627 {
2628 if(comp->document)
2629 {
2630 return comp->document->GetTitle();
2631 }
2632 }
2633
2634 static const std::string empty;
2635 return empty;
2636}
2637
2638void internal_m2n_ui_document_set_title(entt::entity id, const std::string& title)
2639{
2640 if(auto comp = safe_get_component<ui_document_component>(id))
2641 {
2642 if(comp->document)
2643 {
2644 comp->document->SetTitle(title);
2645 }
2646 }
2647}
2648
2649//-------------------------------------------------------------------------
2650/*
2651
2652 ______ _ ______ __ __ ______ _ _ _______
2653 | ____| | | ____| \/ | ____| \ | |__ __|
2654 | |__ | | | |__ | \ / | |__ | \| | | |
2655 | __| | | | __| | |\/| | __| | . ` | | |
2656 | |____| |____| |____| | | | |____| |\ | | |
2657 |______|______|______|_| |_|______|_| \_| |_|
2658
2659
2660*/
2661//-------------------------------------------------------------------------
2662
2663// Helper function to get UI element safely
2664auto get_ui_element_safe(entt::entity entity_id, const std::string& element_id) -> Rml::Element*
2665{
2666 if(auto comp = safe_get_component<ui_document_component>(entity_id))
2667 {
2668 if(comp->document)
2669 {
2670 return comp->document->GetElementById(element_id);
2671 }
2672 }
2673 return nullptr;
2674}
2675
2676
2677//-------------------------------------------------------------------------
2678/*
2679
2680 ______ _ _ ______ _ _ _______ _____ _ _ ____ _____ _ __ _____
2681 | ____| | | | ____| \ | |__ __| / ____| /\ | | | | | _ \ /\ / ____| |/ // ____|
2682 | |__ | | | | |__ | \| | | | | | / \ | | | | | |_) | / \ | | | ' /| (___
2683 | __| | | | | __| | . ` | | | | | / /\ \ | | | | | _ < / /\ \| | | < \___ \
2684 | |____| |__| | |____| |\ | | | | |____ / ____ \| |____| |____| |_) / ____ \ |____| . \ ____) |
2685 |______|\____/|______|_| \_| |_| \_____/_/ \_\______|______|____/_/ \_\_____|_|\_\_____/
2686
2687
2688*/
2689//-------------------------------------------------------------------------
2690
2691// Forward declaration for event dispatching to UIEventManager
2692
2693// Legacy dispatch event to C# UIEventManager (kept for backward compatibility)
2694template<typename T>
2695void dispatch_ui_event_to_manager(const T& event_data)
2696{
2697 try
2698 {
2699 auto& ctx = engine::context();
2700 auto& script_sys = ctx.get<script_system>();
2701 auto assembly = script_sys.get_engine_assembly();
2702
2703 // Get the UIEventManager type
2704 auto ui_event_manager_type = assembly.get_type("Unravel.Core", "UIEventManager");
2705 if (!ui_event_manager_type.valid())
2706 {
2707 APPLOG_ERROR("UIEventManager type not found in assembly");
2708 return;
2709 }
2710
2711 // Get the InternalDispatchEvent method
2712 auto dispatch_method = ui_event_manager_type.get_method("InternalDispatchEvent");
2713 if (!dispatch_method.valid())
2714 {
2715 APPLOG_ERROR("UIEventManager.InternalDispatchEvent method not found");
2716 return;
2717 }
2718
2719 // Create method invoker and call it
2720 auto method_invoker = mono::make_method_invoker<void(const T&)>(dispatch_method, true);
2721 if (method_invoker.valid())
2722 {
2723 method_invoker(event_data);
2724 }
2725 else
2726 {
2727 APPLOG_ERROR("Failed to create method invoker for UIEventManager.InternalDispatchEvent");
2728 }
2729 }
2730 catch (const mono::mono_exception& e)
2731 {
2732 APPLOG_ERROR("Mono exception dispatching UI event: {}", e.what());
2733 }
2734 catch (const std::exception& e)
2735 {
2736 APPLOG_ERROR("Error dispatching UI event: {}", e.what());
2737 }
2738}
2739
2740
2741
2742// UI Event Type Classification
2743enum class ui_event_type
2744{
2745 unknown,
2746 key,
2747 textinput,
2748 pointer,
2749 change,
2750 value
2751};
2752
2753// Determine UI event type for efficient dispatch
2754auto get_ui_event_type(const Rml::Event& event) -> ui_event_type
2755{
2756 const auto event_id = event.GetId();
2757
2758 // Check key events first (most common check)
2759 if (event_id == Rml::EventId::Keydown || event_id == Rml::EventId::Keyup)
2760 {
2761 return ui_event_type::key;
2762 }
2763
2764 // Check text input events
2765 if (event_id == Rml::EventId::Textinput)
2766 {
2767 return ui_event_type::textinput;
2768 }
2769
2770 // Check pointer events
2771 if (event_id == Rml::EventId::Click || event_id == Rml::EventId::Mousedown || event_id == Rml::EventId::Mouseup ||
2772 event_id == Rml::EventId::Mousemove || event_id == Rml::EventId::Mouseover || event_id == Rml::EventId::Mouseout ||
2773 event_id == Rml::EventId::Mousescroll || event_id == Rml::EventId::Dblclick || event_id == Rml::EventId::Drag ||
2774 event_id == Rml::EventId::Dragstart || event_id == Rml::EventId::Dragover || event_id == Rml::EventId::Dragdrop)
2775 {
2776 return ui_event_type::pointer;
2777 }
2778
2779 // Check change events (need to examine the event more closely)
2780 if (event_id == Rml::EventId::Change)
2781 {
2782 auto value_str = event.GetParameter<std::string>("value", "");
2783 if (!value_str.empty())
2784 {
2785 // If the element doesn't have min/max attributes, it's likely a text input or similar (change event)
2786 if (auto* element = event.GetCurrentElement())
2787 {
2788 if (!element->HasAttribute("min") && !element->HasAttribute("max"))
2789 {
2790 return ui_event_type::change;
2791 }
2792 else
2793 {
2794 // Has min/max attributes, likely a slider (value event)
2795 return ui_event_type::value;
2796 }
2797 }
2798 }
2799 }
2800
2801 return ui_event_type::unknown;
2802}
2803
2804
2805// Fill base event data common to all event types
2806void fill_base_event_data(mono::managed_interface::ui_event_base& event_data,
2807 const Rml::Event& event,
2808 Rml::Element* target_element,
2809 Rml::Element* current_element)
2810{
2811 event_data.native_ptr = reinterpret_cast<std::intptr_t>(&event);
2812 event_data.target_element_id = target_element->GetId();
2813 event_data.target_element_ptr = reinterpret_cast<std::intptr_t>(target_element);
2814 event_data.current_element_id = current_element->GetId();
2815 event_data.current_element_ptr = reinterpret_cast<std::intptr_t>(current_element);
2816 event_data.event_type = event.GetType();
2817 event_data.phase = static_cast<int>(event.GetPhase());
2818}
2819
2820// Dispatch key event to C# UIEventManager
2821void dispatch_key_event_to_manager(const Rml::Event& event,
2822 Rml::Element* target_element,
2823 Rml::Element* current_element)
2824{
2825
2826 // Create key event data
2828 fill_base_event_data(key_event_data, event, target_element, current_element);
2829
2830 // Fill key-specific data based on actual RmlUi parameters
2831 auto key_identifier = event.GetParameter<int>("key_identifier", 0);
2832 key_event_data.key_code = RmlEngine::convert_rml_key_to_input(static_cast<Rml::Input::KeyIdentifier>(key_identifier));
2833 key_event_data.ctrl_key = event.GetParameter<int>("ctrl_key", 0) > 0;
2834 key_event_data.shift_key = event.GetParameter<int>("shift_key", 0) > 0;
2835 key_event_data.alt_key = event.GetParameter<int>("alt_key", 0) > 0;
2836 key_event_data.meta_key = event.GetParameter<int>("meta_key", 0) > 0;
2837
2838 dispatch_ui_event_to_manager(key_event_data);
2839}
2840
2841// Dispatch pointer event to C# UIEventManager
2842void dispatch_pointer_event_to_manager(const Rml::Event& event,
2843 Rml::Element* target_element,
2844 Rml::Element* current_element)
2845{
2846
2847 // Create pointer event data
2849 fill_base_event_data(pointer_event_data, event, target_element, current_element);
2850
2851 // Fill pointer-specific data based on actual RmlUi parameters
2852 pointer_event_data.x = event.GetParameter<float>("mouse_x", 0.0f);
2853 pointer_event_data.y = event.GetParameter<float>("mouse_y", 0.0f);
2854 pointer_event_data.button = event.GetParameter<int>("button", -1);
2855 pointer_event_data.ctrl_key = event.GetParameter<int>("ctrl_key", 0) > 0;
2856 pointer_event_data.shift_key = event.GetParameter<int>("shift_key", 0) > 0;
2857 pointer_event_data.alt_key = event.GetParameter<int>("alt_key", 0) > 0;
2858 pointer_event_data.meta_key = event.GetParameter<int>("meta_key", 0) > 0;
2859 pointer_event_data.delta_x = event.GetParameter<float>("wheel_delta_x", 0.0f);
2860 pointer_event_data.delta_y = event.GetParameter<float>("wheel_delta_y", 0.0f);
2861
2862 dispatch_ui_event_to_manager(pointer_event_data);
2863
2864}
2865
2866// Dispatch text input event to C# UIEventManager
2867void dispatch_textinput_event_to_manager(const Rml::Event& event,
2868 Rml::Element* target_element,
2869 Rml::Element* current_element)
2870{
2871 // Create text input event data
2873 fill_base_event_data(textinput_event_data, event, target_element, current_element);
2874
2875
2876 // Fill text input-specific data
2877 textinput_event_data.text = event.GetParameter<std::string>("text", "");
2878 textinput_event_data.ctrl_key = event.GetParameter<int>("ctrl_key", 0) > 0;
2879 textinput_event_data.shift_key = event.GetParameter<int>("shift_key", 0) > 0;
2880 textinput_event_data.alt_key = event.GetParameter<int>("alt_key", 0) > 0;
2881 textinput_event_data.meta_key = event.GetParameter<int>("meta_key", 0) > 0;
2882
2883
2884 dispatch_ui_event_to_manager(textinput_event_data);
2885}
2886
2887// Dispatch value event to C# UIEventManager
2888void dispatch_value_event_to_manager(const Rml::Event& event,
2889 Rml::Element* target_element,
2890 Rml::Element* current_element)
2891{
2892
2893 // Create value event data
2895 fill_base_event_data(value_event_data, event, target_element, current_element);
2896
2897 // Fill value-specific data
2898 value_event_data.value = event.GetParameter<float>("value", 0);
2899
2900 if(auto* slider_element = event.GetCurrentElement())
2901 {
2902 value_event_data.min_value = slider_element->GetAttribute<float>("min", 0);
2903 value_event_data.max_value = slider_element->GetAttribute<float>("max", 0);
2904 value_event_data.step = slider_element->GetAttribute<float>("step", 0);
2905 }
2906
2907 dispatch_ui_event_to_manager(value_event_data);
2908}
2909
2910// Dispatch change event to C# UIEventManager
2911void dispatch_change_event_to_manager(const Rml::Event& event,
2912 Rml::Element* target_element,
2913 Rml::Element* current_element)
2914{
2915
2916 // Create change event data
2918 fill_base_event_data(change_event_data, event, target_element, current_element);
2919
2920 // Fill change-specific data
2921 change_event_data.value = event.GetParameter<std::string>("value", "");
2922
2923 dispatch_ui_event_to_manager(change_event_data);
2924
2925}
2926
2927// Dispatch base event to C# UIEventManager (fallback)
2928void dispatch_base_event_to_manager(const Rml::Event& event,
2929 Rml::Element* target_element,
2930 Rml::Element* current_element)
2931{
2933 fill_base_event_data(event_data, event, target_element, current_element);
2934 dispatch_ui_event_to_manager(event_data);
2935}
2936
2937// Global event listener that dispatches all UI events to C# UIEventManager
2938class ui_global_event_listener : public Rml::EventListener
2939{
2940 Rml::Event* current_event_ = nullptr;
2941public:
2942 void ProcessEvent(Rml::Event& event) override
2943 {
2944 current_event_ = &event;
2945 try
2946 {
2947 // Get event information
2948 auto* target_element = event.GetTargetElement();
2949 if (!target_element)
2950 {
2951 return;
2952 }
2953
2954 auto* current_element = event.GetCurrentElement();
2955 if (!current_element)
2956 {
2957 return;
2958 }
2959
2960 // Determine event type and dispatch accordingly using efficient switch
2961 const auto event_type = get_ui_event_type(event);
2962
2963 switch (event_type)
2964 {
2965 case ui_event_type::key:
2966 dispatch_key_event_to_manager(event, target_element, current_element);
2967 break;
2968
2969 case ui_event_type::textinput:
2970 dispatch_textinput_event_to_manager(event, target_element, current_element);
2971 break;
2972
2973 case ui_event_type::pointer:
2974 dispatch_pointer_event_to_manager(event, target_element, current_element);
2975 break;
2976
2977 case ui_event_type::change:
2978 dispatch_change_event_to_manager(event, target_element, current_element);
2979 break;
2980
2981 case ui_event_type::value:
2982 dispatch_value_event_to_manager(event, target_element, current_element);
2983 break;
2984
2985 case ui_event_type::unknown:
2986 default:
2987 // Fallback to base event for unknown types
2988 dispatch_base_event_to_manager(event, target_element, current_element);
2989 break;
2990 }
2991 }
2992 catch (const std::exception& e)
2993 {
2994 APPLOG_ERROR("Error processing UI event: {}", e.what());
2995 }
2996 current_event_ = nullptr;
2997 }
2998
2999 // Allow access to current event for propagation control
3000 auto get_current_event() const -> Rml::Event*
3001 {
3002 return current_event_;
3003 }
3004};
3005
3006// Global event listener instance
3007ui_global_event_listener g_ui_global_listener;
3008
3009// Ensure a native event listener is attached to the element for the given event type
3010void internal_m2n_ui_ensure_native_event_listener(std::intptr_t element_ptr, const std::string& event_type)
3011{
3012 if (element_ptr == 0)
3013 {
3014 return;
3015 }
3016
3017 try
3018 {
3019 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3020
3021 // Add event listener to the element
3022 // Note: RmlUi handles duplicate listeners internally, so it's safe to call this multiple times
3023 element->AddEventListener(event_type, &g_ui_global_listener);
3024
3025 APPLOG_TRACE("Ensured native UI event listener: element='{}', event='{}'", element->GetId(), event_type);
3026 }
3027 catch (const mono::mono_exception& e)
3028 {
3029 APPLOG_ERROR("Mono exception ensuring native UI event listener: {}", e.what());
3030 }
3031 catch (const std::exception& e)
3032 {
3033 APPLOG_ERROR("Error ensuring native UI event listener: {}", e.what());
3034 }
3035}
3036
3037// Stop event propagation - called from C# UIEventBase.StopPropagation()
3038void internal_m2n_ui_stop_propagation(std::intptr_t native_ptr)
3039{
3040 try
3041 {
3042
3043 auto* current_event = g_ui_global_listener.get_current_event();
3044 if (current_event && current_event == reinterpret_cast<Rml::Event*>(native_ptr))
3045 {
3046 current_event->StopPropagation();
3047 }
3048 else
3049 {
3050 APPLOG_WARNING("No current UI event to stop propagation on");
3051 }
3052
3053 }
3054 catch (const std::exception& e)
3055 {
3056 APPLOG_ERROR("Error stopping UI event propagation: {}", e.what());
3057 }
3058}
3059
3060// Stop immediate event propagation - called from C# UIEventBase.StopImmediatePropagation()
3061void internal_m2n_ui_stop_immediate_propagation(std::intptr_t native_ptr)
3062{
3063 try
3064 {
3065 auto* current_event = g_ui_global_listener.get_current_event();
3066 if (current_event)
3067 {
3068 current_event->StopImmediatePropagation();
3069 }
3070 else
3071 {
3072 APPLOG_WARNING("No current UI event to stop immediate propagation on");
3073 }
3074 }
3075 catch (const std::exception& e)
3076 {
3077 APPLOG_ERROR("Error stopping UI event immediate propagation: {}", e.what());
3078 }
3079}
3080
3081//-------------------------------------------------------------------------
3082/*
3083
3084 _ _ _____ __ _______ _____ _____ ______ _____ _____
3085 | | | |_ _| \ \ / / __ \ /\ | __ \| __ \| ____| __ \ / ____|
3086 | | | | | | \ \ /\ / /| |__) | / \ | |__) | |__) | |__ | |__) || (___
3087 | | | | | | \ \/ \/ / | _ / / /\ \ | ___/| ___/| __| | _ / \___ \
3088 | |__| |_| |_ \ /\ / | | \ \ / ____ \ | | | | | |____| | \ \ ____) |
3089 \____/|_____| \/ \/ |_| \_\/_/ \_\|_| |_| |______|_| \_\|_____/
3090
3091
3092*/
3093//-------------------------------------------------------------------------
3094
3095// Helper function to validate element pointer by checking if it exists in any UI document
3096auto validate_ui_element_wrapper(std::intptr_t element_ptr) -> bool
3097{
3098 if (element_ptr == 0)
3099 {
3100 return false;
3101 }
3102
3103 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3104
3105 // Check if this element exists in any loaded UI document
3106 auto& ctx = engine::context();
3107 auto& ec = ctx.get_cached<ecs>();
3108 auto& scene = ec.get_scene();
3109 auto& registry = *scene.registry;
3110
3111 auto view = registry.view<ui_document_component>();
3112 for (auto entity : view)
3113 {
3114 auto& ui_comp = view.get<ui_document_component>(entity);
3115 if (ui_comp.document)
3116 {
3117 // Check if this element belongs to this document
3118 if (ui_comp.document->Contains(element))
3119 {
3120 return true;
3121 }
3122 }
3123 }
3124
3125 return false;
3126}
3127
3128// Helper function to validate document pointer by checking if it matches any UI component
3129auto validate_ui_document_wrapper(std::intptr_t document_ptr) -> bool
3130{
3131 if (document_ptr == 0)
3132 {
3133 return false;
3134 }
3135
3136 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3137
3138 // Check if this document exists in any UI component
3139 auto& ctx = engine::context();
3140 auto& ec = ctx.get_cached<ecs>();
3141 auto& scene = ec.get_scene();
3142 auto& registry = *scene.registry;
3143
3144 auto view = registry.view<ui_document_component>();
3145 for (auto entity : view)
3146 {
3147 auto& ui_comp = view.get<ui_document_component>(entity);
3148 if (ui_comp.document && ui_comp.document == document)
3149 {
3150 return true;
3151 }
3152 }
3153
3154 return false;
3155}
3156
3157//-------------------------------------------------------------------------
3158// UI Document Wrapper Functions
3159//-------------------------------------------------------------------------
3160
3161auto internal_m2n_ui_document_get_wrapper(entt::entity entity_id) -> std::intptr_t
3162{
3163 if (auto comp = safe_get_component<ui_document_component>(entity_id))
3164 {
3165 if (comp->document)
3166 {
3167 return reinterpret_cast<std::intptr_t>(comp->document);
3168 }
3169 }
3170 return 0;
3171}
3172
3173auto internal_m2n_ui_document_get_element_wrapper_by_id(std::intptr_t document_ptr, const std::string& element_id) -> std::intptr_t
3174{
3175 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3176 if (document)
3177 {
3178 auto* element = document->GetElementById(element_id);
3179 return reinterpret_cast<std::intptr_t>(element);
3180 }
3181
3182 return 0;
3183}
3184
3185auto internal_m2n_ui_document_query_selector_wrapper(std::intptr_t document_ptr, const std::string& selector) -> std::intptr_t
3186{
3187 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3188 if (document)
3189 {
3190 auto element = document->QuerySelector(selector);
3191 if (element)
3192 {
3193 return reinterpret_cast<std::intptr_t>(element);
3194 }
3195 }
3196
3197 return 0;
3198}
3199
3200// Get element ID from element pointer
3201auto internal_m2n_ui_element_wrapper_get_id(std::intptr_t element_ptr) -> std::string
3202{
3203 if (!validate_ui_element_wrapper(element_ptr))
3204 {
3205 return "";
3206 }
3207
3208 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3209 return element->GetId();
3210}
3211
3212//-------------------------------------------------------------------------
3213// UI Document Wrapper Methods
3214//-------------------------------------------------------------------------
3215
3216auto internal_m2n_ui_document_wrapper_is_valid(std::intptr_t document_ptr) -> bool
3217{
3218 return validate_ui_document_wrapper(document_ptr);
3219}
3220
3221auto internal_m2n_ui_document_wrapper_get_title(std::intptr_t document_ptr) -> std::string
3222{
3223 if (!validate_ui_document_wrapper(document_ptr))
3224 {
3225 return "";
3226 }
3227
3228 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3229 return document->GetTitle();
3230}
3231
3232void internal_m2n_ui_document_wrapper_set_title(std::intptr_t document_ptr, const std::string& title)
3233{
3234 if (!validate_ui_document_wrapper(document_ptr))
3235 {
3236 return;
3237 }
3238
3239 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3240 document->SetTitle(title);
3241}
3242
3243auto internal_m2n_ui_document_wrapper_is_visible(std::intptr_t document_ptr) -> bool
3244{
3245 if (!validate_ui_document_wrapper(document_ptr))
3246 {
3247 return false;
3248 }
3249
3250 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3251 return document->IsVisible();
3252}
3253
3254void internal_m2n_ui_document_wrapper_show(std::intptr_t document_ptr)
3255{
3256 if (!validate_ui_document_wrapper(document_ptr))
3257 {
3258 return;
3259 }
3260
3261 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3262 document->Show();
3263}
3264
3265void internal_m2n_ui_document_wrapper_hide(std::intptr_t document_ptr)
3266{
3267 if (!validate_ui_document_wrapper(document_ptr))
3268 {
3269 return;
3270 }
3271
3272 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3273 document->Hide();
3274}
3275
3276void internal_m2n_ui_document_wrapper_close(std::intptr_t document_ptr)
3277{
3278 if (!validate_ui_document_wrapper(document_ptr))
3279 {
3280 return;
3281 }
3282
3283 auto* document = reinterpret_cast<Rml::ElementDocument*>(document_ptr);
3284 document->Close();
3285}
3286
3287//-------------------------------------------------------------------------
3288// UI Element Wrapper Methods
3289//-------------------------------------------------------------------------
3290
3291auto internal_m2n_ui_element_wrapper_is_valid(std::intptr_t element_ptr) -> bool
3292{
3293 return validate_ui_element_wrapper(element_ptr);
3294}
3295
3296auto internal_m2n_ui_element_wrapper_get_inner_rml(std::intptr_t element_ptr) -> std::string
3297{
3298 if (!validate_ui_element_wrapper(element_ptr))
3299 {
3300 return "";
3301 }
3302
3303 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3304 return element->GetInnerRML();
3305}
3306
3307void internal_m2n_ui_element_wrapper_set_inner_rml(std::intptr_t element_ptr, const std::string& rml)
3308{
3309 if (!validate_ui_element_wrapper(element_ptr))
3310 {
3311 return;
3312 }
3313
3314 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3315 element->SetInnerRML(rml);
3316}
3317
3318auto internal_m2n_ui_element_wrapper_is_visible(std::intptr_t element_ptr) -> bool
3319{
3320 if (!validate_ui_element_wrapper(element_ptr))
3321 {
3322 return false;
3323 }
3324
3325 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3326 return element->IsVisible();
3327}
3328
3329void internal_m2n_ui_element_wrapper_set_visible(std::intptr_t element_ptr, bool visible)
3330{
3331 if (!validate_ui_element_wrapper(element_ptr))
3332 {
3333 return;
3334 }
3335
3336 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3337 if (visible)
3338 {
3339 element->SetProperty("display", "block");
3340 }
3341 else
3342 {
3343 element->SetProperty("display", "none");
3344 }
3345}
3346
3347auto internal_m2n_ui_element_wrapper_get_attribute(std::intptr_t element_ptr, const std::string& attribute_name) -> std::string
3348{
3349 if (!validate_ui_element_wrapper(element_ptr))
3350 {
3351 return "";
3352 }
3353
3354 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3355 return element->GetAttribute<Rml::String>(attribute_name, "");
3356}
3357
3358void internal_m2n_ui_element_wrapper_set_attribute(std::intptr_t element_ptr, const std::string& attribute_name, const std::string& value)
3359{
3360 if (!validate_ui_element_wrapper(element_ptr))
3361 {
3362 return;
3363 }
3364
3365 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3366 element->SetAttribute(attribute_name, value);
3367}
3368
3369void internal_m2n_ui_element_wrapper_remove_attribute(std::intptr_t element_ptr, const std::string& attribute_name)
3370{
3371 if (!validate_ui_element_wrapper(element_ptr))
3372 {
3373 return;
3374 }
3375
3376 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3377 element->RemoveAttribute(attribute_name);
3378}
3379
3380auto internal_m2n_ui_element_wrapper_has_attribute(std::intptr_t element_ptr, const std::string& attribute_name) -> bool
3381{
3382 if (!validate_ui_element_wrapper(element_ptr))
3383 {
3384 return false;
3385 }
3386
3387 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3388 return element->HasAttribute(attribute_name);
3389}
3390
3391void internal_m2n_ui_element_wrapper_set_class(std::intptr_t element_ptr, const std::string& class_name, bool activate)
3392{
3393 if (!validate_ui_element_wrapper(element_ptr))
3394 {
3395 return;
3396 }
3397
3398 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3399 element->SetClass(class_name, activate);
3400}
3401
3402auto internal_m2n_ui_element_wrapper_is_class_set(std::intptr_t element_ptr, const std::string& class_name) -> bool
3403{
3404 if (!validate_ui_element_wrapper(element_ptr))
3405 {
3406 return false;
3407 }
3408
3409 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3410 return element->IsClassSet(class_name);
3411}
3412
3413void internal_m2n_ui_element_wrapper_focus(std::intptr_t element_ptr)
3414{
3415 if (!validate_ui_element_wrapper(element_ptr))
3416 {
3417 return;
3418 }
3419
3420 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3421 element->Focus();
3422}
3423
3424void internal_m2n_ui_element_wrapper_blur(std::intptr_t element_ptr)
3425{
3426 if (!validate_ui_element_wrapper(element_ptr))
3427 {
3428 return;
3429 }
3430
3431 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3432 element->Blur();
3433}
3434
3435void internal_m2n_ui_element_wrapper_click(std::intptr_t element_ptr)
3436{
3437 if (!validate_ui_element_wrapper(element_ptr))
3438 {
3439 return;
3440 }
3441
3442 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3443 element->Click();
3444}
3445
3446void internal_m2n_ui_element_wrapper_scroll_into_view(std::intptr_t element_ptr, bool align_with_top)
3447{
3448 if (!validate_ui_element_wrapper(element_ptr))
3449 {
3450 return;
3451 }
3452
3453 auto* element = reinterpret_cast<Rml::Element*>(element_ptr);
3454 element->ScrollIntoView(align_with_top);
3455}
3456
3457
3458//--------------------------------------------------
3459} // namespace
3460
3461auto script_system::bind_internal_calls(rtti::context& ctx) -> bool
3462{
3463 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
3464
3465 {
3466 auto reg = mono::internal_call_registry("Unravel.Core.Log");
3467 reg.add_internal_call("internal_m2n_log_trace", internal_call(internal_m2n_log_trace));
3468 reg.add_internal_call("internal_m2n_log_info", internal_call(internal_m2n_log_info));
3469 reg.add_internal_call("internal_m2n_log_warning", internal_call(internal_m2n_log_warning));
3470 reg.add_internal_call("internal_m2n_log_error", internal_call(internal_m2n_log_error));
3471 }
3472
3473 {
3474 auto reg = mono::internal_call_registry("Unravel.Core.Scene");
3475 reg.add_internal_call("internal_m2n_load_scene", internal_call(internal_m2n_load_scene));
3476 reg.add_internal_call("internal_m2n_load_scene_uid", internal_call(internal_m2n_load_scene_uid));
3477 reg.add_internal_call("internal_m2n_create_scene", internal_call(internal_m2n_create_scene));
3478 reg.add_internal_call("internal_m2n_destroy_scene", internal_call(internal_m2n_destroy_scene));
3479 reg.add_internal_call("internal_m2n_create_entity", internal_call(internal_m2n_create_entity));
3480 reg.add_internal_call("internal_m2n_create_entity_from_prefab_uid",
3481 internal_call(internal_m2n_create_entity_from_prefab_uid));
3482 reg.add_internal_call("internal_m2n_create_entity_from_prefab_key",
3483 internal_call(internal_m2n_create_entity_from_prefab_key));
3484 reg.add_internal_call("internal_m2n_clone_entity", internal_call(internal_m2n_clone_entity));
3485 reg.add_internal_call("internal_m2n_destroy_entity", internal_call(internal_m2n_destroy_entity));
3486 reg.add_internal_call("internal_m2n_destroy_entity_immediate",
3487 internal_call(internal_m2n_destroy_entity_immediate));
3488
3489 reg.add_internal_call("internal_m2n_is_entity_valid", internal_call(internal_m2n_is_entity_valid));
3490 reg.add_internal_call("internal_m2n_find_entity_by_name", internal_call(internal_m2n_find_entity_by_name));
3491 reg.add_internal_call("internal_m2n_find_entities_by_name", internal_call(internal_m2n_find_entities_by_name));
3492 reg.add_internal_call("internal_m2n_find_entity_by_tag", internal_call(internal_m2n_find_entity_by_tag));
3493 reg.add_internal_call("internal_m2n_find_entities_by_tag", internal_call(internal_m2n_find_entities_by_tag));
3494 }
3495
3496 {
3497 auto reg = mono::internal_call_registry("Unravel.Core.Entity");
3498 reg.add_internal_call("internal_m2n_add_component", internal_call(internal_m2n_add_component));
3499 reg.add_internal_call("internal_m2n_get_component", internal_call(internal_m2n_get_component));
3500 reg.add_internal_call("internal_m2n_get_component_in_children",
3501 internal_call(internal_m2n_get_component_in_children));
3502 reg.add_internal_call("internal_m2n_has_component", internal_call(internal_m2n_has_component));
3503 reg.add_internal_call("internal_m2n_get_components", internal_call(internal_m2n_get_components));
3504 reg.add_internal_call("internal_m2n_get_components_in_children",
3505 internal_call(internal_m2n_get_components_in_children));
3506
3507 reg.add_internal_call("internal_m2n_remove_component_instance",
3508 internal_call(internal_m2n_remove_component_instance));
3509 reg.add_internal_call("internal_m2n_remove_component_instance_delay",
3510 internal_call(internal_m2n_remove_component_instance_delay));
3511
3512 reg.add_internal_call("internal_m2n_remove_component", internal_call(internal_m2n_remove_component));
3513 reg.add_internal_call("internal_m2n_remove_component_delay",
3514 internal_call(internal_m2n_remove_component_delay));
3515
3516 reg.add_internal_call("internal_m2n_get_transform_component",
3517 internal_call(internal_m2n_get_transform_component));
3518 reg.add_internal_call("internal_m2n_get_name", internal_call(internal_m2n_get_name));
3519 reg.add_internal_call("internal_m2n_set_name", internal_call(internal_m2n_set_name));
3520 reg.add_internal_call("internal_m2n_get_tag", internal_call(internal_m2n_get_tag));
3521 reg.add_internal_call("internal_m2n_set_tag", internal_call(internal_m2n_set_tag));
3522 reg.add_internal_call("internal_m2n_get_layers", internal_call(internal_m2n_get_layers));
3523 reg.add_internal_call("internal_m2n_set_layers", internal_call(internal_m2n_set_layers));
3524
3525 reg.add_internal_call("internal_m2n_get_active_global", internal_call(internal_m2n_get_active_global));
3526 reg.add_internal_call("internal_m2n_get_active_local", internal_call(internal_m2n_get_active_local));
3527 reg.add_internal_call("internal_m2n_set_active_local", internal_call(internal_m2n_set_active_local));
3528 }
3529
3530 {
3531 auto reg = mono::internal_call_registry("Unravel.Core.TransformComponent");
3532 reg.add_internal_call("internal_m2n_get_children", internal_call(internal_m2n_get_children));
3533 reg.add_internal_call("internal_m2n_get_child", internal_call(internal_m2n_get_child));
3534 reg.add_internal_call("internal_m2n_get_parent", internal_call(internal_m2n_get_parent));
3535 reg.add_internal_call("internal_m2n_set_parent", internal_call(internal_m2n_set_parent));
3536
3537 reg.add_internal_call("internal_m2n_get_position_global", internal_call(internal_m2n_get_position_global));
3538 reg.add_internal_call("internal_m2n_set_position_global", internal_call(internal_m2n_set_position_global));
3539 reg.add_internal_call("internal_m2n_move_by_global", internal_call(internal_m2n_move_by_global));
3540
3541 reg.add_internal_call("internal_m2n_get_position_local", internal_call(internal_m2n_get_position_local));
3542 reg.add_internal_call("internal_m2n_set_position_local", internal_call(internal_m2n_set_position_local));
3543 reg.add_internal_call("internal_m2n_move_by_local", internal_call(internal_m2n_move_by_local));
3544
3545 // Euler
3546 reg.add_internal_call("internal_m2n_get_rotation_euler_global",
3547 internal_call(internal_m2n_get_rotation_euler_global));
3548 reg.add_internal_call("internal_m2n_set_rotation_euler_global",
3549 internal_call(internal_m2n_set_rotation_euler_global));
3550 reg.add_internal_call("internal_m2n_rotate_by_euler_global",
3551 internal_call(internal_m2n_rotate_by_euler_global));
3552
3553 reg.add_internal_call("internal_m2n_get_rotation_euler_local",
3554 internal_call(internal_m2n_get_rotation_euler_local));
3555 reg.add_internal_call("internal_m2n_set_rotation_euler_local",
3556 internal_call(internal_m2n_set_rotation_euler_local));
3557 reg.add_internal_call("internal_m2n_rotate_by_euler_local", internal_call(internal_m2n_rotate_by_euler_local));
3558
3559 // Quat
3560 reg.add_internal_call("internal_m2n_get_rotation_global", internal_call(internal_m2n_get_rotation_global));
3561 reg.add_internal_call("internal_m2n_set_rotation_global", internal_call(internal_m2n_set_rotation_global));
3562 reg.add_internal_call("internal_m2n_rotate_by_global", internal_call(internal_m2n_rotate_by_global));
3563
3564 reg.add_internal_call("internal_m2n_get_rotation_local", internal_call(internal_m2n_get_rotation_local));
3565 reg.add_internal_call("internal_m2n_set_rotation_local", internal_call(internal_m2n_set_rotation_local));
3566 reg.add_internal_call("internal_m2n_rotate_by_local", internal_call(internal_m2n_rotate_by_local));
3567
3568 // Other
3569 reg.add_internal_call("internal_m2n_rotate_axis_global", internal_call(internal_m2n_rotate_axis_global));
3570 reg.add_internal_call("internal_m2n_look_at", internal_call(internal_m2n_look_at));
3571 reg.add_internal_call("internal_m2n_transform_vector_global",
3572 internal_call(internal_m2n_transform_vector_global));
3573 reg.add_internal_call("internal_m2n_inverse_transform_vector_global",
3574 internal_call(internal_m2n_inverse_transform_vector_global));
3575
3576 reg.add_internal_call("internal_m2n_transform_direction_global",
3577 internal_call(internal_m2n_transform_direction_global));
3578 reg.add_internal_call("internal_m2n_inverse_transform_direction_global",
3579 internal_call(internal_m2n_inverse_transform_direction_global));
3580
3581 // Scale
3582 reg.add_internal_call("internal_m2n_get_scale_global", internal_call(internal_m2n_get_scale_global));
3583 reg.add_internal_call("internal_m2n_set_scale_global", internal_call(internal_m2n_set_scale_global));
3584 reg.add_internal_call("internal_m2n_scale_by_global", internal_call(internal_m2n_scale_by_local));
3585
3586 reg.add_internal_call("internal_m2n_get_scale_local", internal_call(internal_m2n_get_scale_local));
3587 reg.add_internal_call("internal_m2n_set_scale_local", internal_call(internal_m2n_set_scale_local));
3588 reg.add_internal_call("internal_m2n_scale_by_local", internal_call(internal_m2n_scale_by_local));
3589
3590 // Skew
3591 reg.add_internal_call("internal_m2n_get_skew_global", internal_call(internal_m2n_get_skew_global));
3592 reg.add_internal_call("internal_m2n_set_skew_globa", internal_call(internal_m2n_setl_skew_globa));
3593 reg.add_internal_call("internal_m2n_get_skew_local", internal_call(internal_m2n_get_skew_local));
3594 reg.add_internal_call("internal_m2n_set_skew_local", internal_call(internal_m2n_set_skew_local));
3595 }
3596
3597 {
3598 auto reg = mono::internal_call_registry("Unravel.Core.PhysicsComponent");
3599 reg.add_internal_call("internal_m2n_physics_apply_explosion_force",
3600 internal_call(internal_m2n_physics_apply_explosion_force));
3601 reg.add_internal_call("internal_m2n_physics_apply_force", internal_call(internal_m2n_physics_apply_force));
3602 reg.add_internal_call("internal_m2n_physics_apply_torque", internal_call(internal_m2n_physics_apply_torque));
3603 reg.add_internal_call("internal_m2n_physics_get_velocity", internal_call(internal_m2n_physics_get_velocity));
3604 reg.add_internal_call("internal_m2n_physics_set_velocity", internal_call(internal_m2n_physics_set_velocity));
3605 reg.add_internal_call("internal_m2n_physics_get_angular_velocity",
3606 internal_call(internal_m2n_physics_get_angular_velocity));
3607 reg.add_internal_call("internal_m2n_physics_set_angular_velocity",
3608 internal_call(internal_m2n_physics_set_angular_velocity));
3609
3610 reg.add_internal_call("internal_m2n_physics_get_include_layers",
3611 internal_call(internal_m2n_physics_get_include_layers));
3612 reg.add_internal_call("internal_m2n_physics_set_include_layers",
3613 internal_call(internal_m2n_physics_set_include_layers));
3614 reg.add_internal_call("internal_m2n_physics_get_exclude_layers",
3615 internal_call(internal_m2n_physics_get_exclude_layers));
3616 reg.add_internal_call("internal_m2n_physics_set_exclude_layers",
3617 internal_call(internal_m2n_physics_set_exclude_layers));
3618 reg.add_internal_call("internal_m2n_physics_get_collision_layers",
3619 internal_call(internal_m2n_physics_get_collision_layers));
3620 }
3621
3622 {
3623 auto reg = mono::internal_call_registry("Unravel.Core.AnimationComponent");
3624 reg.add_internal_call("internal_m2n_animation_blend", internal_call(internal_m2n_animation_blend));
3625 reg.add_internal_call("internal_m2n_animation_play", internal_call(internal_m2n_animation_play));
3626 reg.add_internal_call("internal_m2n_animation_pause", internal_call(internal_m2n_animation_pause));
3627 reg.add_internal_call("internal_m2n_animation_resume", internal_call(internal_m2n_animation_resume));
3628 reg.add_internal_call("internal_m2n_animation_stop", internal_call(internal_m2n_animation_stop));
3629 reg.add_internal_call("internal_m2n_animation_set_speed", internal_call(internal_m2n_animation_set_speed));
3630 reg.add_internal_call("internal_m2n_animation_get_speed", internal_call(internal_m2n_animation_get_speed));
3631 }
3632
3633 {
3634 auto reg = mono::internal_call_registry("Unravel.Core.CameraComponent");
3635 reg.add_internal_call("internal_m2n_camera_screen_point_to_ray",
3636 internal_call(internal_m2n_camera_screen_point_to_ray));
3637 }
3638
3639 {
3640 auto reg = mono::internal_call_registry("Unravel.Core.ModelComponent");
3641 reg.add_internal_call("internal_m2n_model_get_enabled", internal_call(internal_m2n_model_get_enabled));
3642 reg.add_internal_call("internal_m2n_model_set_enabled", internal_call(internal_m2n_model_set_enabled));
3643 reg.add_internal_call("internal_m2n_model_get_shared_material",
3644 internal_call(internal_m2n_model_get_shared_material));
3645 reg.add_internal_call("internal_m2n_model_get_shared_material_count",
3646 internal_call(internal_m2n_model_get_shared_material_count));
3647 reg.add_internal_call("internal_m2n_model_set_shared_material",
3648 internal_call(internal_m2n_model_set_shared_material));
3649 reg.add_internal_call("internal_m2n_model_set_material_instance",
3650 internal_call(internal_m2n_model_set_material_instance));
3651 reg.add_internal_call("internal_m2n_model_get_material_instance",
3652 internal_call(internal_m2n_model_get_material_instance));
3653 reg.add_internal_call("internal_m2n_model_get_material_instance_count",
3654 internal_call(internal_m2n_model_get_material_instance_count));
3655 }
3656
3657 {
3658 auto reg = mono::internal_call_registry("Unravel.Core.TextComponent");
3659 reg.add_internal_call("internal_m2n_text_get_text", internal_call(internal_m2n_text_get_text));
3660 reg.add_internal_call("internal_m2n_text_set_text", internal_call(internal_m2n_text_set_text));
3661 reg.add_internal_call("internal_m2n_text_get_buffer_type", internal_call(internal_m2n_text_get_buffer_type));
3662 reg.add_internal_call("internal_m2n_text_set_buffer_type", internal_call(internal_m2n_text_set_buffer_type));
3663 reg.add_internal_call("internal_m2n_text_get_overflow_type",
3664 internal_call(internal_m2n_text_get_overflow_type));
3665 reg.add_internal_call("internal_m2n_text_set_overflow_type",
3666 internal_call(internal_m2n_text_set_overflow_type));
3667 reg.add_internal_call("internal_m2n_text_get_font", internal_call(internal_m2n_text_get_font));
3668 reg.add_internal_call("internal_m2n_text_set_font", internal_call(internal_m2n_text_set_font));
3669
3670 reg.add_internal_call("internal_m2n_text_get_font_size", internal_call(internal_m2n_text_get_font_size));
3671 reg.add_internal_call("internal_m2n_text_set_font_size", internal_call(internal_m2n_text_set_font_size));
3672 reg.add_internal_call("internal_m2n_text_get_render_font_size",
3673 internal_call(internal_m2n_text_get_render_font_size));
3674
3675 reg.add_internal_call("internal_m2n_text_get_auto_size", internal_call(internal_m2n_text_get_auto_size));
3676 reg.add_internal_call("internal_m2n_text_set_auto_size", internal_call(internal_m2n_text_set_auto_size));
3677
3678 reg.add_internal_call("internal_m2n_text_get_auto_size_range",
3679 internal_call(internal_m2n_text_get_auto_size_range));
3680 reg.add_internal_call("internal_m2n_text_set_auto_size_range",
3681 internal_call(internal_m2n_text_set_auto_size_range));
3682
3683 reg.add_internal_call("internal_m2n_text_get_area", internal_call(internal_m2n_text_get_area));
3684 reg.add_internal_call("internal_m2n_text_set_area", internal_call(internal_m2n_text_set_area));
3685 reg.add_internal_call("internal_m2n_text_get_render_area", internal_call(internal_m2n_text_get_render_area));
3686
3687 reg.add_internal_call("internal_m2n_text_get_is_rich_text", internal_call(internal_m2n_text_get_is_rich_text));
3688 reg.add_internal_call("internal_m2n_text_set_is_rich_text", internal_call(internal_m2n_text_set_is_rich_text));
3689
3690 reg.add_internal_call("internal_m2n_text_get_alignment", internal_call(internal_m2n_text_get_alignment));
3691 reg.add_internal_call("internal_m2n_text_set_alignment", internal_call(internal_m2n_text_set_alignment));
3692
3693 reg.add_internal_call("internal_m2n_text_get_bounds", internal_call(internal_m2n_text_get_bounds));
3694 reg.add_internal_call("internal_m2n_text_get_render_bounds", internal_call(internal_m2n_text_get_bounds));
3695 }
3696
3697 {
3698 auto reg = mono::internal_call_registry("Unravel.Core.LightComponent");
3699 reg.add_internal_call("internal_m2n_light_get_color", internal_call(internal_m2n_light_get_color));
3700 reg.add_internal_call("internal_m2n_light_set_color", internal_call(internal_m2n_light_set_color));
3701 }
3702
3703 {
3704 auto reg = mono::internal_call_registry("Unravel.Core.Assets");
3705 reg.add_internal_call("internal_m2n_get_asset_by_uuid", internal_call(internal_m2n_get_asset_by_uuid));
3706 reg.add_internal_call("internal_m2n_get_asset_by_key", internal_call(internal_m2n_get_asset_by_key));
3707 reg.add_internal_call("internal_m2n_get_material_properties",
3708 internal_call(internal_m2n_get_material_properties));
3709 }
3710
3711 {
3712 auto reg = mono::internal_call_registry("Unravel.Core.AudioClip");
3713 reg.add_internal_call("internal_m2n_audio_clip_get_length", internal_call(internal_m2n_audio_clip_get_length));
3714 }
3715
3716 {
3717 auto reg = mono::internal_call_registry("Quaternion");
3718 reg.add_internal_call("internal_m2n_from_euler_rad", internal_call(internal_m2n_from_euler_rad));
3719 reg.add_internal_call("internal_m2n_to_euler_rad", internal_call(internal_m2n_to_euler_rad));
3720 reg.add_internal_call("internal_m2n_from_to_rotation", internal_call(internal_m2n_from_to_rotation));
3721 reg.add_internal_call("internal_m2n_angle_axis", internal_call(internal_m2n_angle_axis));
3722 reg.add_internal_call("internal_m2n_look_rotation", internal_call(internal_m2n_look_rotation));
3723 }
3724
3725 {
3726 auto reg = mono::internal_call_registry("Unravel.Core.Gizmos");
3727 reg.add_internal_call("internal_m2n_gizmos_add_sphere", internal_call(internal_m2n_gizmos_add_sphere));
3728 reg.add_internal_call("internal_m2n_gizmos_add_ray", internal_call(internal_m2n_gizmos_add_ray));
3729 }
3730
3731 {
3732 auto reg = mono::internal_call_registry("Unravel.Core.Tests");
3733 reg.add_internal_call("m2n_test_uuid", internal_call(m2n_test_uuid));
3734 }
3735
3736 {
3737 auto reg = mono::internal_call_registry("Unravel.Core.LayerMask");
3738 reg.add_internal_call("internal_m2n_layers_layer_to_name", internal_call(internal_m2n_layers_layer_to_name));
3739 reg.add_internal_call("internal_m2n_layers_name_to_layer", internal_call(internal_m2n_layers_name_to_layer));
3740 }
3741
3742 {
3743 auto reg = mono::internal_call_registry("Unravel.Core.Input");
3744 reg.add_internal_call("internal_m2n_input_get_analog_value",
3745 internal_call(internal_m2n_input_get_analog_value));
3746 reg.add_internal_call("internal_m2n_input_get_digital_value",
3747 internal_call(internal_m2n_input_get_analog_value));
3748 reg.add_internal_call("internal_m2n_input_is_pressed", internal_call(internal_m2n_input_is_pressed));
3749 reg.add_internal_call("internal_m2n_input_is_released", internal_call(internal_m2n_input_is_released));
3750 reg.add_internal_call("internal_m2n_input_is_down", internal_call(internal_m2n_input_is_down));
3751 reg.add_internal_call("internal_m2n_input_is_key_pressed", internal_call(internal_m2n_input_is_key_pressed));
3752 reg.add_internal_call("internal_m2n_input_is_key_released", internal_call(internal_m2n_input_is_key_released));
3753 reg.add_internal_call("internal_m2n_input_is_key_down", internal_call(internal_m2n_input_is_key_down));
3754 reg.add_internal_call("internal_m2n_input_is_mouse_button_pressed",
3755 internal_call(internal_m2n_input_is_mouse_button_pressed));
3756 reg.add_internal_call("internal_m2n_input_is_mouse_button_released",
3757 internal_call(internal_m2n_input_is_mouse_button_released));
3758 reg.add_internal_call("internal_m2n_input_is_mouse_button_down",
3759 internal_call(internal_m2n_input_is_mouse_button_down));
3760 reg.add_internal_call("internal_m2n_input_get_mouse_position",
3761 internal_call(internal_m2n_input_get_mouse_position));
3762 }
3763
3764 {
3765 auto reg = mono::internal_call_registry("Unravel.Core.Physics");
3766 reg.add_internal_call("internal_m2n_physics_ray_cast", internal_call(internal_m2n_physics_ray_cast));
3767 reg.add_internal_call("internal_m2n_physics_ray_cast_all", internal_call(internal_m2n_physics_ray_cast_all));
3768 reg.add_internal_call("internal_m2n_physics_sphere_cast", internal_call(internal_m2n_physics_sphere_cast));
3769 reg.add_internal_call("internal_m2n_physics_sphere_cast_all",
3770 internal_call(internal_m2n_physics_sphere_cast_all));
3771 reg.add_internal_call("internal_m2n_physics_sphere_overlap",
3772 internal_call(internal_m2n_physics_sphere_overlap));
3773 }
3774
3775 {
3776 auto reg = mono::internal_call_registry("Unravel.Core.IK");
3777 reg.add_internal_call("internal_m2n_utils_set_ik_posiiton_ccd",
3778 internal_call(internal_m2n_utils_set_ik_posiiton_ccd));
3779 reg.add_internal_call("internal_m2n_utils_set_ik_posiiton_fabrik",
3780 internal_call(internal_m2n_utils_set_ik_posiiton_fabrik));
3781 reg.add_internal_call("internal_m2n_utils_set_ik_posiiton_two_bone",
3782 internal_call(internal_m2n_utils_set_ik_posiiton_two_bone));
3783
3784 reg.add_internal_call("internal_m2n_utils_set_ik_look_at_posiiton",
3785 internal_call(internal_m2n_utils_set_ik_look_at_posiiton));
3786 }
3787
3788 {
3789 auto reg = mono::internal_call_registry("Unravel.Core.AudioSourceComponent");
3790 reg.add_internal_call("internal_m2n_audio_source_get_loop", internal_call(internal_m2n_audio_source_get_loop));
3791 reg.add_internal_call("internal_m2n_audio_source_set_loop", internal_call(internal_m2n_audio_source_set_loop));
3792 reg.add_internal_call("internal_m2n_audio_source_get_volume",
3793 internal_call(internal_m2n_audio_source_get_volume));
3794 reg.add_internal_call("internal_m2n_audio_source_set_volume",
3795 internal_call(internal_m2n_audio_source_set_volume));
3796 reg.add_internal_call("internal_m2n_audio_source_get_pitch",
3797 internal_call(internal_m2n_audio_source_get_pitch));
3798 reg.add_internal_call("internal_m2n_audio_source_set_pitch",
3799 internal_call(internal_m2n_audio_source_set_pitch));
3800 reg.add_internal_call("internal_m2n_audio_source_get_volume_rolloff",
3801 internal_call(internal_m2n_audio_source_get_volume_rolloff));
3802 reg.add_internal_call("internal_m2n_audio_source_set_volume_rolloff",
3803 internal_call(internal_m2n_audio_source_set_volume_rolloff));
3804 reg.add_internal_call("internal_m2n_audio_source_get_min_distance",
3805 internal_call(internal_m2n_audio_source_get_min_distance));
3806 reg.add_internal_call("internal_m2n_audio_source_set_min_distance",
3807 internal_call(internal_m2n_audio_source_set_min_distance));
3808 reg.add_internal_call("internal_m2n_audio_source_get_max_distance",
3809 internal_call(internal_m2n_audio_source_get_max_distance));
3810 reg.add_internal_call("internal_m2n_audio_source_set_max_distance",
3811 internal_call(internal_m2n_audio_source_set_max_distance));
3812 reg.add_internal_call("internal_m2n_audio_source_get_mute", internal_call(internal_m2n_audio_source_get_mute));
3813
3814 reg.add_internal_call("internal_m2n_audio_source_set_mute", internal_call(internal_m2n_audio_source_set_mute));
3815
3816 reg.add_internal_call("internal_m2n_audio_source_is_playing",
3817 internal_call(internal_m2n_audio_source_is_playing));
3818 reg.add_internal_call("internal_m2n_audio_source_is_paused",
3819 internal_call(internal_m2n_audio_source_is_paused));
3820 reg.add_internal_call("internal_m2n_audio_source_play", internal_call(internal_m2n_audio_source_play));
3821 reg.add_internal_call("internal_m2n_audio_source_stop", internal_call(internal_m2n_audio_source_stop));
3822
3823 reg.add_internal_call("internal_m2n_audio_source_pause", internal_call(internal_m2n_audio_source_pause));
3824 reg.add_internal_call("internal_m2n_audio_source_resume", internal_call(internal_m2n_audio_source_resume));
3825 reg.add_internal_call("internal_m2n_audio_source_get_audio_clip",
3826 internal_call(internal_m2n_audio_source_get_audio_clip));
3827 reg.add_internal_call("internal_m2n_audio_source_set_audio_clip",
3828 internal_call(internal_m2n_audio_source_set_audio_clip));
3829 }
3830
3831 {
3832 auto reg = mono::internal_call_registry("Unravel.Core.UIDocumentComponent");
3833 reg.add_internal_call("internal_m2n_ui_document_get_asset", internal_call(internal_m2n_ui_document_get_asset));
3834 reg.add_internal_call("internal_m2n_ui_document_set_asset", internal_call(internal_m2n_ui_document_set_asset));
3835 reg.add_internal_call("internal_m2n_ui_document_is_loaded", internal_call(internal_m2n_ui_document_is_loaded));
3836 reg.add_internal_call("internal_m2n_ui_document_is_enabled", internal_call(internal_m2n_ui_document_is_enabled));
3837 reg.add_internal_call("internal_m2n_ui_document_set_enabled", internal_call(internal_m2n_ui_document_set_enabled));
3838 reg.add_internal_call("internal_m2n_ui_document_close", internal_call(internal_m2n_ui_document_close));
3839 reg.add_internal_call("internal_m2n_ui_document_get_title", internal_call(internal_m2n_ui_document_get_title));
3840 reg.add_internal_call("internal_m2n_ui_document_set_title", internal_call(internal_m2n_ui_document_set_title));
3841 reg.add_internal_call("internal_m2n_ui_document_get_wrapper", internal_call(internal_m2n_ui_document_get_wrapper));
3842 }
3843
3844
3845 {
3846 auto reg = mono::internal_call_registry("Unravel.Core.UIDocument");
3847 reg.add_internal_call("internal_m2n_ui_document_wrapper_is_valid", internal_call(internal_m2n_ui_document_wrapper_is_valid));
3848 reg.add_internal_call("internal_m2n_ui_document_wrapper_get_title", internal_call(internal_m2n_ui_document_wrapper_get_title));
3849 reg.add_internal_call("internal_m2n_ui_document_wrapper_set_title", internal_call(internal_m2n_ui_document_wrapper_set_title));
3850 reg.add_internal_call("internal_m2n_ui_document_wrapper_is_visible", internal_call(internal_m2n_ui_document_wrapper_is_visible));
3851 reg.add_internal_call("internal_m2n_ui_document_wrapper_show", internal_call(internal_m2n_ui_document_wrapper_show));
3852 reg.add_internal_call("internal_m2n_ui_document_wrapper_hide", internal_call(internal_m2n_ui_document_wrapper_hide));
3853 reg.add_internal_call("internal_m2n_ui_document_wrapper_close", internal_call(internal_m2n_ui_document_wrapper_close));
3854 reg.add_internal_call("internal_m2n_ui_document_wrapper_get_element_by_id", internal_call(internal_m2n_ui_document_get_element_wrapper_by_id));
3855 reg.add_internal_call("internal_m2n_ui_document_wrapper_query_selector", internal_call(internal_m2n_ui_document_query_selector_wrapper));
3856 reg.add_internal_call("internal_m2n_ui_document_wrapper_query_selector_all", internal_call(internal_m2n_ui_document_query_selector_wrapper));
3857 }
3858
3859 {
3860 auto reg = mono::internal_call_registry("Unravel.Core.UIElement");
3861 reg.add_internal_call("internal_m2n_ui_element_wrapper_is_valid", internal_call(internal_m2n_ui_element_wrapper_is_valid));
3862 reg.add_internal_call("internal_m2n_ui_element_wrapper_get_inner_rml", internal_call(internal_m2n_ui_element_wrapper_get_inner_rml));
3863 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_inner_rml", internal_call(internal_m2n_ui_element_wrapper_set_inner_rml));
3864 reg.add_internal_call("internal_m2n_ui_element_wrapper_is_visible", internal_call(internal_m2n_ui_element_wrapper_is_visible));
3865 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_visible", internal_call(internal_m2n_ui_element_wrapper_set_visible));
3866 reg.add_internal_call("internal_m2n_ui_element_wrapper_get_attribute", internal_call(internal_m2n_ui_element_wrapper_get_attribute));
3867 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_attribute", internal_call(internal_m2n_ui_element_wrapper_set_attribute));
3868 reg.add_internal_call("internal_m2n_ui_element_wrapper_remove_attribute", internal_call(internal_m2n_ui_element_wrapper_remove_attribute));
3869 reg.add_internal_call("internal_m2n_ui_element_wrapper_has_attribute", internal_call(internal_m2n_ui_element_wrapper_has_attribute));
3870 reg.add_internal_call("internal_m2n_ui_element_wrapper_set_class", internal_call(internal_m2n_ui_element_wrapper_set_class));
3871 reg.add_internal_call("internal_m2n_ui_element_wrapper_is_class_set", internal_call(internal_m2n_ui_element_wrapper_is_class_set));
3872 reg.add_internal_call("internal_m2n_ui_element_wrapper_focus", internal_call(internal_m2n_ui_element_wrapper_focus));
3873 reg.add_internal_call("internal_m2n_ui_element_wrapper_blur", internal_call(internal_m2n_ui_element_wrapper_blur));
3874 reg.add_internal_call("internal_m2n_ui_element_wrapper_click", internal_call(internal_m2n_ui_element_wrapper_click));
3875 reg.add_internal_call("internal_m2n_ui_element_wrapper_scroll_into_view", internal_call(internal_m2n_ui_element_wrapper_scroll_into_view));
3876 reg.add_internal_call("internal_m2n_ui_element_wrapper_get_id", internal_call(internal_m2n_ui_element_wrapper_get_id));
3877 }
3878
3879 {
3880 auto reg = mono::internal_call_registry("Unravel.Core.UIEventManager");
3881 reg.add_internal_call("internal_m2n_ui_ensure_native_event_listener", internal_call(internal_m2n_ui_ensure_native_event_listener));
3882 }
3883
3884 {
3885 auto reg = mono::internal_call_registry("Unravel.Core.UIEventBase");
3886 reg.add_internal_call("internal_m2n_ui_stop_propagation", internal_call(internal_m2n_ui_stop_propagation));
3887 reg.add_internal_call("internal_m2n_ui_stop_immediate_propagation", internal_call(internal_m2n_ui_stop_immediate_propagation));
3888 }
3889
3890 {
3891 auto reg = mono::internal_call_registry("Unravel.Core.Application");
3892 reg.add_internal_call("internal_m2n_application_quit", internal_call(internal_m2n_application_quit));
3893 }
3894
3895 {
3896 auto reg = mono::internal_call_registry("Unravel.Core.Time");
3897 reg.add_internal_call("internal_m2n_set_time_scale", internal_call(internal_m2n_set_time_scale));
3898 }
3899
3900 // mono::managed_interface::init(assembly);
3901
3902 return true;
3903}
3904
3905} // namespace unravel
manifold_type type
int layer_mask
bool query_sensors
event_type event
unravel::physics_vector< hit_info > hits
animation_clip::seconds_t seconds_t
std::shared_ptr< material > sptr
Definition material.h:36
std::chrono::duration< float > delta_t
float scale
Definition hub.cpp:25
ImGui::Font::Enum font
Definition hub.cpp:24
std::string name
Definition hub.cpp:27
std::string tag
Definition hub.cpp:26
#define APPLOG_WARNING(...)
Definition logging.h:19
#define APPLOG_ERROR(...)
Definition logging.h:20
#define APPLOG_INFO(...)
Definition logging.h:18
#define APPLOG_INFO_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:34
#define APPLOG_WARNING_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:36
#define APPLOG_ERROR_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:38
#define APPLOG_TRACE_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:32
#define APPLOG_TRACE(...)
Definition logging.h:17
auto look_rotation(const glm::vec3 &forward, const glm::vec3 &upwards) -> glm::quat
auto from_to_rotation(const glm::vec3 &from, const glm::vec3 &to) -> glm::quat
key_code
Definition key.hpp:6
auto start(seq_action action, const seq_scope_policy &scope_policy, hpp::source_location location) -> seq_id_t
Starts a new action.
Definition seq.cpp:8
auto delay(const duration_t &duration, const sentinel_t &sentinel) -> seq_action
Creates a delay action.
Definition seq_core.cpp:182
auto tokenize(const std::string &str, const std::string &delimiters) -> string_tokens_t
Definition utils.cpp:136
auto convert_rml_key_to_input(Rml::Input::KeyIdentifier rml_key) -> input::key_code
Convert RmlUi key identifier to engine input key code.
auto ik_set_position_ccd(entt::handle end_effector, const math::vec3 &target, size_t num_bones_in_chain, float threshold, int max_iterations) -> bool
auto generate_uuid() -> hpp::uuid
Definition uuid.cpp:25
@ nothing_layer
Definition layer_mask.h:13
@ sphere
Sphere type reflection probe.
auto ik_set_position_two_bone(entt::handle end_effector, const math::vec3 &target, const math::vec3 &forward, float weight, float soften, int max_iterations) -> bool
hpp::small_vector< T, SmallSizeCapacity > physics_vector
auto ik_set_position_fabrik(entt::handle end_effector, const math::vec3 &target, size_t num_bones_in_chain, float threshold, int max_iterations) -> bool
auto ik_look_at_position(entt::handle end_effector, const math::vec3 &target, float weight) -> bool
bool is_valid(octet_iterator start, octet_iterator end)
Definition core.h:467
std::function< bool(size_t type_hash, entt::handle e)> has_native
entt::entity entity
size_t matched_index
std::function< bool(size_t type_hash, entt::handle e)> remove_native
std::function< bool(size_t type_hash, entt::handle e)> add_native
float distance
void draw(const bx::Aabb &_aabb)
void lineTo(float _x, float _y, float _z=0.0f)
void setColor(uint32_t _abgr)
void setWireframe(bool _wireframe)
void moveTo(float _x, float _y, float _z=0.0f)
DebugDrawEncoder encoder
Definition debugdraw.h:15
Storage for box vector values and wraps up common functionality.
Definition bbox.h:21
static bbox empty
An empty bounding box.
Definition bbox.h:316
static color white()
Definition math.h:287
static auto context() -> rtti::context &
Definition engine.cpp:115