Unravel Engine C++ Reference
Loading...
Searching...
No Matches
script_component.cpp
Go to the documentation of this file.
1#include "script_component.h"
2#include <monopp/mono_property.h>
3#include <monopp/mono_property_invoker.h>
4
6#include <engine/engine.h>
7#include <engine/events.h>
9namespace unravel
10{
11
12namespace
13{
14
15struct managed_vector3
16{
17 float x, y, z;
18};
19
20struct managed_contact_point
21{
22 managed_vector3 point{};
23 managed_vector3 normal{};
24 float distance{};
25 float impulse{};
26};
27
28} // namespace
29
30void script_component::on_create_component(entt::registry& r, entt::entity e)
31{
32 entt::handle entity(r, e);
33
34 auto& component = entity.get<script_component>();
35 component.set_owner(entity);
36}
37
38void script_component::on_destroy_component(entt::registry& r, entt::entity e)
39{
40}
41
52
54{
55 safe_foreach(script_components_,
56 [&](auto& script)
57 {
58 auto& obj = script.scoped->object;
60 });
61
63}
64
66{
67 safe_foreach(script_components_,
68 [&](auto& script)
69 {
70 auto& obj = script.scoped->object;
71 enable(script, true);
72 });
73}
74
76{
77 safe_foreach(script_components_,
78 [&](auto& script)
79 {
80 auto& obj = script.scoped->object;
81 disable(script, true);
82 });
83}
84
85void script_component::on_sensor_enter(entt::handle other)
86{
87 safe_foreach(script_components_,
88 [&](auto& script)
89 {
90 auto& obj = script.scoped->object;
91 on_sensor_enter(obj, other);
92 });
93}
94
95void script_component::on_sensor_exit(entt::handle other)
96{
97 safe_foreach(script_components_,
98 [&](auto& script)
99 {
100 auto& obj = script.scoped->object;
101 on_sensor_exit(obj, other);
102 });
103}
104
105void script_component::on_collision_enter(entt::handle b, const std::vector<manifold_point>& manifolds, bool use_b)
106{
107 safe_foreach(script_components_,
108 [&](auto& script)
109 {
110 auto& obj = script.scoped->object;
111 on_collision_enter(obj, b, manifolds, use_b);
112 });
113}
114
115void script_component::on_collision_exit(entt::handle b, const std::vector<manifold_point>& manifolds, bool use_b)
116{
117 safe_foreach(script_components_,
118 [&](auto& script)
119 {
120 auto& obj = script.scoped->object;
121 on_collision_exit(obj, b, manifolds, use_b);
122 });
123}
124
125void script_component::enable(script_object& script_obj, bool check_order)
126{
127 if(script_obj.is_enabled() || script_obj.is_marked_for_destroy())
128 {
129 return;
130 }
131
132 script_obj.state->active = true;
133
134 if(check_order)
135 {
136 if(!script_obj.is_create_called())
137 {
138 return;
139 }
140 }
141
142 auto& obj = script_obj.scoped->object;
143
144 obj.get_type().get_method("OnCollisionEnter", 1);
145
146 try
147 {
148 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_enable");
149 method(obj);
150 }
151 catch(const mono::mono_exception& e)
152 {
154 }
155}
156
157void script_component::disable(script_object& script_obj, bool check_order)
158{
159 if(script_obj.is_disabled() || script_obj.is_marked_for_destroy())
160 {
161 return;
162 }
163
164 script_obj.state->active = 0;
165
166 if(check_order)
167 {
168 if(!script_obj.is_create_called())
169 {
170 return;
171 }
172 }
173 auto& obj = script_obj.scoped->object;
174
175 try
176 {
177 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_disable");
178 method(obj);
179 }
180 catch(const mono::mono_exception& e)
181 {
183 }
184}
185
186void script_component::create(script_object& script_obj)
187{
188 if(script_obj.is_create_called())
189 {
190 return;
191 }
192
193 script_obj.state->create_called = true;
194 auto& obj = script_obj.scoped->object;
195
196 try
197 {
198 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_create");
199 method(obj);
200 }
201 catch(const mono::mono_exception& e)
202 {
204 }
205}
206void script_component::start(script_object& script_obj)
207{
208 if(script_obj.is_start_called())
209 {
210 return;
211 }
212 script_obj.state->start_called = true;
213 auto& obj = script_obj.scoped->object;
214
215 try
216 {
217 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_start");
218 method(obj);
219 }
220 catch(const mono::mono_exception& e)
221 {
223 }
224}
225
226void script_component::destroy(script_object& script_obj)
227{
228 auto& obj = script_obj.scoped->object;
229 try
230 {
231 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_destroy");
232 method(obj);
233 }
234 catch(const mono::mono_exception& e)
235 {
237 }
238}
239
240void script_component::set_entity(const mono::mono_object& obj, entt::handle e)
241{
242 try
243 {
244 auto method = mono::make_method_invoker<void(entt::entity)>(obj, "internal_n2m_set_entity");
245 method(obj, e.entity());
246 }
247 catch(const mono::mono_exception& e)
248 {
250 }
251}
252
253void script_component::on_sensor_enter(const mono::mono_object& obj, entt::handle other)
254{
255 try
256 {
257 auto method = mono::make_method_invoker<void(entt::entity)>(obj, "internal_n2m_on_sensor_enter");
258 method(obj, other.entity());
259 }
260 catch(const mono::mono_exception& e)
261 {
263 }
264}
265
266void script_component::on_sensor_exit(const mono::mono_object& obj, entt::handle other)
267{
268 try
269 {
270 auto method = mono::make_method_invoker<void(entt::entity)>(obj, "internal_n2m_on_sensor_exit");
271 method(obj, other.entity());
272 }
273 catch(const mono::mono_exception& e)
274 {
276 }
277}
278
279void script_component::on_collision_enter(const mono::mono_object& obj,
280 entt::handle b,
281 const std::vector<manifold_point>& manifolds,
282 bool use_b)
283{
284 std::vector<managed_contact_point> points;
285 points.reserve(manifolds.size());
286 for(const auto& manifold : manifolds)
287 {
288 auto& point = points.emplace_back();
289 if(use_b)
290 {
291 point.point = {manifold.b.x, manifold.b.y, manifold.b.z};
292 point.normal = {manifold.normal_on_b.x, manifold.normal_on_b.y, manifold.normal_on_b.z};
293 }
294 else
295 {
296 point.point = {manifold.a.x, manifold.a.y, manifold.a.z};
297 point.normal = {manifold.normal_on_a.x, manifold.normal_on_a.y, manifold.normal_on_a.z};
298 }
299 point.distance = manifold.distance;
300 point.impulse = manifold.impulse;
301 }
302
303 try
304 {
305 auto method = mono::make_method_invoker<void(entt::entity, const std::vector<managed_contact_point>&)>(
306 obj,
307 "internal_n2m_on_collision_enter");
308 method(obj, b.entity(), points);
309 }
310 catch(const mono::mono_exception& e)
311 {
313 }
314}
315
316void script_component::on_collision_exit(const mono::mono_object& obj,
317 entt::handle b,
318 const std::vector<manifold_point>& manifolds,
319 bool use_b)
320{
321 std::vector<managed_contact_point> points;
322 points.reserve(manifolds.size());
323 for(const auto& manifold : manifolds)
324 {
325 auto& point = points.emplace_back();
326 if(use_b)
327 {
328 point.point = {manifold.b.x, manifold.b.y, manifold.b.z};
329 point.normal = {manifold.normal_on_b.x, manifold.normal_on_b.y, manifold.normal_on_b.z};
330 }
331 else
332 {
333 point.point = {manifold.a.x, manifold.a.y, manifold.a.z};
334 point.normal = {manifold.normal_on_a.x, manifold.normal_on_a.y, manifold.normal_on_a.z};
335 }
336 point.distance = manifold.distance;
337 point.impulse = manifold.impulse;
338 }
339
340 try
341 {
342 auto method = mono::make_method_invoker<void(entt::entity, const std::vector<managed_contact_point>&)>(
343 obj,
344 "internal_n2m_on_collision_exit");
345 method(obj, b.entity(), points);
346 }
347 catch(const mono::mono_exception& e)
348 {
350 }
351}
352
354{
355 auto& ctx = engine::context();
356 auto& ev = ctx.get_cached<events>();
357
358 size_t erased = std::erase_if(script_components_,
359 [&](auto& rhs)
360 {
361 bool marked = rhs.is_marked_for_destroy();
362 if(marked && ev.is_playing)
363 {
364 destroy(rhs);
365 }
366
367 return marked;
368 });
369
370 erased += std::erase_if(native_components_,
371 [&](const auto& rhs)
372 {
373 return rhs.is_marked_for_destroy();
374 });
375}
376
378{
379 while(!script_components_to_create_.empty())
380 {
381 auto comps = std::move(script_components_to_create_);
382 script_components_to_create_.clear();
383
384 for(auto& script : comps)
385 {
386 if(!script.is_marked_for_destroy())
387 {
388 create(script);
389 }
390 }
391 }
392}
393
395{
396 while(!script_components_to_start_.empty())
397 {
398 auto comps = std::move(script_components_to_start_);
399 script_components_to_start_.clear();
400
401 for(auto& script : comps)
402 {
403 if(!script.is_marked_for_destroy())
404 {
405 start(script);
406 }
407 }
408 }
409}
410
415
417{
418 auto& ctx = engine::context();
419 auto& sys = ctx.get_cached<script_system>();
420 auto& ev = ctx.get_cached<events>();
421
422 if(ev.is_playing && sys.is_create_called())
423 {
425
426 if(get_owner().all_of<active_component>())
427 {
428 enable(script_obj, false);
429 }
430 else
431 {
432 disable(script_obj, false);
433 }
434 }
435}
436
437
439{
440 auto obj = type.new_instance();
441 return add_script_component(obj);
442}
443
444auto script_component::add_script_component(const mono::mono_object& obj) -> script_object
445{
446 script_object script_obj(obj);
447 return add_script_component(script_obj);
448}
449
450auto script_component::add_script_component(const script_object& script_obj, bool process_callbacks) -> script_object
451{
452 script_components_.emplace_back(script_obj);
453 script_components_to_create_.emplace_back(script_obj);
454 script_components_to_start_.emplace_back(script_obj);
455
456 auto& obj = script_obj.scoped->object;
457
458 set_entity(obj, get_owner());
459
460 if(process_callbacks)
461 {
462 process_pending_actions(script_obj);
463 }
464
465 return script_obj;
466}
467
469{
470 for(auto& comp : comps)
471 {
472 if(comp.scoped)
473 {
474 add_script_component(comp, false);
475 }
476 }
477}
478
480{
481 for(auto& comp : comps)
482 {
483 if(comp.scoped)
484 {
485 auto& obj = comp.scoped->object;
486 const auto& type = obj.get_type();
487 if(get_script_component(type).scoped)
488 {
489 continue;
490 }
491
493 }
494 }
495}
496
498{
499 auto obj = type.new_instance();
500 auto& script_obj = native_components_.emplace_back(obj);
501
502 set_entity(obj, get_owner());
503
504 return script_obj;
505}
506
507auto script_component::get_script_components(const mono::mono_type& type) -> std::vector<mono::mono_object>
508{
509 std::vector<mono::mono_object> result;
510 for(const auto& component : script_components_)
511 {
512 const auto& comp_type = component.scoped->object.get_type();
513
514 if(comp_type.get_internal_ptr() == type.get_internal_ptr() || comp_type.is_derived_from(type))
515 {
516 result.emplace_back(static_cast<mono::mono_object&>(component.scoped->object));
517 }
518 }
519
520 return result;
521}
522
524{
525 auto it = std::find_if(std::begin(script_components_),
526 std::end(script_components_),
527 [&](const auto& component)
528 {
529 const auto& comp_type = component.scoped->object.get_type();
530 return comp_type.get_internal_ptr() == type.get_internal_ptr() ||
531 comp_type.is_derived_from(type);
532 });
533
534 if(it != std::end(script_components_))
535 {
536 return *it;
537 }
538
539 return {};
540}
541
543{
544 auto it = std::find_if(std::begin(native_components_),
545 std::end(native_components_),
546 [&](const auto& component)
547 {
548 const auto& comp_type = component.scoped->object.get_type();
549 return comp_type.get_internal_ptr() == type.get_internal_ptr() ||
550 comp_type.is_derived_from(type);
551 });
552
553 if(it != std::end(native_components_))
554 {
555 return *it;
556 }
557
558 return {};
559}
560
561auto script_component::remove_script_component(const mono::mono_object& obj) -> bool
562{
563 auto checker = [&](const auto& rhs)
564 {
565 return rhs.scoped->object.get_internal_ptr() == obj.get_internal_ptr();
566 };
567 std::erase_if(script_components_to_create_, checker);
568
569 std::erase_if(script_components_to_start_, checker);
570
571 auto it = std::find_if(std::begin(script_components_), std::end(script_components_), checker);
572
573 if(it != std::end(script_components_))
574 {
575 auto& script_obj = *it;
576
577 set_entity(obj, {});
578
579 script_obj.state->marked_for_destroy = true;
580 return true;
581 }
582
583 return false;
584}
585
586auto script_component::remove_script_component(const mono::mono_type& type) -> bool
587{
588 auto checker = [&](const auto& rhs)
589 {
590 return rhs.scoped->object.get_type().get_internal_ptr() == type.get_internal_ptr();
591 };
592 std::erase_if(script_components_to_create_, checker);
593
594 std::erase_if(script_components_to_start_, checker);
595
596 auto it = std::find_if(std::begin(script_components_), std::end(script_components_), checker);
597
598 if(it != std::end(script_components_))
599 {
600 auto& script_obj = *it;
601 auto& obj = script_obj.scoped->object;
602 set_entity(obj, {});
603
604 script_obj.state->marked_for_destroy = true;
605 return true;
606 }
607
608 return false;
609}
610
611auto script_component::remove_native_component(const mono::mono_object& obj) -> bool
612{
613 auto it = std::find_if(std::begin(native_components_),
614 std::end(native_components_),
615 [&](const auto& rhs)
616 {
617 return rhs.scoped->object.get_internal_ptr() == obj.get_internal_ptr();
618 });
619
620 if(it != std::end(native_components_))
621 {
622 auto& script_obj = *it;
623
624 set_entity(obj, {});
625
626 script_obj.state->marked_for_destroy = true;
627 return true;
628 }
629
630 return false;
631}
632
633auto script_component::remove_native_component(const mono::mono_type& type) -> bool
634{
635 auto it = std::find_if(std::begin(native_components_),
636 std::end(native_components_),
637 [&](const auto& rhs)
638 {
639 return rhs.scoped->object.get_type().get_internal_ptr() == type.get_internal_ptr();
640 });
641
642 if(it != std::end(native_components_))
643 {
644 auto& script_obj = *it;
645
646 auto& obj = script_obj.scoped->object;
647 set_entity(obj, {});
648
649 script_obj.state->marked_for_destroy = true;
650 return true;
651 }
652
653 return false;
654}
655
657{
658 return script_components_;
659}
660
662{
663 return !script_components_.empty();
664}
665
666auto script_component::has_script_components(const std::string& type_name) const -> bool
667{
668 return std::any_of(std::begin(script_components_), std::end(script_components_), [&](const auto& component)
669 {
670 return component.scoped->object.get_type().get_name() == type_name;
671 });
672}
673
675{
676 if(!obj.scoped)
677 {
678 return {};
679 }
680
681 const auto& object = obj.scoped->object;
682 const auto& type = object.get_type();
683 try
684 {
685 auto attrs = type.get_attributes();
686 for(auto& attr : attrs)
687 {
688 if(attr.get_type().get_fullname() == "Unravel.Core.ScriptSourceFileAttribute")
689 {
690 auto invoker = mono::make_property_invoker<std::string>(attr.get_type(), "Path");
691 return invoker.get_value(attr);
692 }
693 }
694 auto prop = type.get_property("SourceFilePath");
695 auto invoker = mono::make_property_invoker<std::string>(prop);
696 return invoker.get_value(object);
697 }
698 catch(const mono::mono_exception& e)
699 {
700 return {};
701 }
702}
703} // namespace unravel
entt::handle b
manifold_type type
btVector3 normal
auto get_owner() const noexcept -> entt::const_handle
Gets the owner of the component.
void set_owner(entt::handle owner)
Sets the owner of the component.
Class that contains core data for audio listeners. There can only be one instance of it per scene.
auto get_script_source_location(const script_object &obj) const -> std::string
void on_collision_enter(entt::handle other, const std::vector< manifold_point > &manifolds, bool use_b)
auto add_native_component(const mono::mono_type &type) -> script_object
void add_missing_script_components(const script_components_t &comps)
auto remove_script_component(const mono::mono_object &obj) -> bool
void on_collision_exit(entt::handle other, const std::vector< manifold_point > &manifolds, bool use_b)
auto get_script_component(const mono::mono_type &type) -> script_object
auto get_native_component(const mono::mono_type &type) -> script_object
void process_pending_actions_create(script_object script_obj)
void add_script_components(const script_components_t &comps)
void on_sensor_enter(entt::handle other)
static void on_destroy_component(entt::registry &r, entt::entity e)
Called when the component is destroyed.
auto get_script_components() const -> const script_components_t &
void on_sensor_exit(entt::handle other)
auto add_script_component(const mono::mono_type &type) -> script_object
auto remove_native_component(const mono::mono_object &obj) -> bool
std::vector< script_object > script_components_t
auto has_script_components() const -> bool
static void on_create_component(entt::registry &r, entt::entity e)
Called when the component is created.
entt::entity entity
float distance
float y
float impulse
float x
float z
point()=default
static auto context() -> rtti::context &
Definition engine.cpp:116
auto is_create_called() const -> bool
static void log_exception(const mono::mono_exception &e, const hpp::source_location &loc=hpp::source_location::current())