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 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_enable");
145 method(obj);
146}
147
148void script_component::disable(script_object& script_obj, bool check_order)
149{
150 if(script_obj.is_disabled() || script_obj.is_marked_for_destroy())
151 {
152 return;
153 }
154
155 script_obj.state->active = 0;
156
157 if(check_order)
158 {
159 if(!script_obj.is_create_called())
160 {
161 return;
162 }
163 }
164 auto& obj = script_obj.scoped->object;
165
166 try
167 {
168 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_disable");
169 method(obj);
170 }
171 catch(const mono::mono_exception& e)
172 {
174 }
175}
176
177void script_component::create(script_object& script_obj)
178{
179 if(script_obj.is_create_called())
180 {
181 return;
182 }
183
184 script_obj.state->create_called = true;
185 auto& obj = script_obj.scoped->object;
186
187 try
188 {
189 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_create");
190 method(obj);
191 }
192 catch(const mono::mono_exception& e)
193 {
195 }
196}
197void script_component::start(script_object& script_obj)
198{
199 if(script_obj.is_start_called())
200 {
201 return;
202 }
203 script_obj.state->start_called = true;
204 auto& obj = script_obj.scoped->object;
205
206 try
207 {
208 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_start");
209 method(obj);
210 }
211 catch(const mono::mono_exception& e)
212 {
214 }
215}
216
217void script_component::destroy(script_object& script_obj)
218{
219 auto& obj = script_obj.scoped->object;
220 try
221 {
222 auto method = mono::make_method_invoker<void()>(obj, "internal_n2m_on_destroy");
223 method(obj);
224 }
225 catch(const mono::mono_exception& e)
226 {
228 }
229}
230
231void script_component::set_entity(const mono::mono_object& obj, entt::handle e)
232{
233 try
234 {
235 auto method = mono::make_method_invoker<void(entt::entity)>(obj, "internal_n2m_set_entity");
236 method(obj, e.entity());
237 }
238 catch(const mono::mono_exception& e)
239 {
241 }
242}
243
244void script_component::on_sensor_enter(const mono::mono_object& obj, entt::handle other)
245{
246 try
247 {
248 auto method = mono::make_method_invoker<void(entt::entity)>(obj, "internal_n2m_on_sensor_enter");
249 method(obj, other.entity());
250 }
251 catch(const mono::mono_exception& e)
252 {
254 }
255}
256
257void script_component::on_sensor_exit(const mono::mono_object& obj, entt::handle other)
258{
259 try
260 {
261 auto method = mono::make_method_invoker<void(entt::entity)>(obj, "internal_n2m_on_sensor_exit");
262 method(obj, other.entity());
263 }
264 catch(const mono::mono_exception& e)
265 {
267 }
268}
269
270void script_component::on_collision_enter(const mono::mono_object& obj,
271 entt::handle b,
272 const std::vector<manifold_point>& manifolds,
273 bool use_b)
274{
275 std::vector<managed_contact_point> points;
276 points.reserve(manifolds.size());
277 for(const auto& manifold : manifolds)
278 {
279 auto& point = points.emplace_back();
280 if(use_b)
281 {
282 point.point = {manifold.b.x, manifold.b.y, manifold.b.z};
283 point.normal = {manifold.normal_on_b.x, manifold.normal_on_b.y, manifold.normal_on_b.z};
284 }
285 else
286 {
287 point.point = {manifold.a.x, manifold.a.y, manifold.a.z};
288 point.normal = {manifold.normal_on_a.x, manifold.normal_on_a.y, manifold.normal_on_a.z};
289 }
290 point.distance = manifold.distance;
291 point.impulse = manifold.impulse;
292 }
293
294 try
295 {
296 auto method = mono::make_method_invoker<void(entt::entity, const std::vector<managed_contact_point>&)>(
297 obj,
298 "internal_n2m_on_collision_enter");
299 method(obj, b.entity(), points);
300 }
301 catch(const mono::mono_exception& e)
302 {
304 }
305}
306
307void script_component::on_collision_exit(const mono::mono_object& obj,
308 entt::handle b,
309 const std::vector<manifold_point>& manifolds,
310 bool use_b)
311{
312 std::vector<managed_contact_point> points;
313 points.reserve(manifolds.size());
314 for(const auto& manifold : manifolds)
315 {
316 auto& point = points.emplace_back();
317 if(use_b)
318 {
319 point.point = {manifold.b.x, manifold.b.y, manifold.b.z};
320 point.normal = {manifold.normal_on_b.x, manifold.normal_on_b.y, manifold.normal_on_b.z};
321 }
322 else
323 {
324 point.point = {manifold.a.x, manifold.a.y, manifold.a.z};
325 point.normal = {manifold.normal_on_a.x, manifold.normal_on_a.y, manifold.normal_on_a.z};
326 }
327 point.distance = manifold.distance;
328 point.impulse = manifold.impulse;
329 }
330
331 try
332 {
333 auto method = mono::make_method_invoker<void(entt::entity, const std::vector<managed_contact_point>&)>(
334 obj,
335 "internal_n2m_on_collision_exit");
336 method(obj, b.entity(), points);
337 }
338 catch(const mono::mono_exception& e)
339 {
341 }
342}
343
345{
346 auto& ctx = engine::context();
347 auto& ev = ctx.get_cached<events>();
348
349 size_t erased = std::erase_if(script_components_,
350 [&](auto& rhs)
351 {
352 bool marked = rhs.is_marked_for_destroy();
353 if(marked && ev.is_playing)
354 {
355 destroy(rhs);
356 }
357
358 return marked;
359 });
360
361 erased += std::erase_if(native_components_,
362 [&](const auto& rhs)
363 {
364 return rhs.is_marked_for_destroy();
365 });
366}
367
369{
370 while(!script_components_to_create_.empty())
371 {
372 auto comps = std::move(script_components_to_create_);
373 script_components_to_create_.clear();
374
375 for(auto& script : comps)
376 {
377 if(!script.is_marked_for_destroy())
378 {
379 create(script);
380 }
381 }
382 }
383}
384
386{
387 while(!script_components_to_start_.empty())
388 {
389 auto comps = std::move(script_components_to_start_);
390 script_components_to_start_.clear();
391
392 for(auto& script : comps)
393 {
394 if(!script.is_marked_for_destroy())
395 {
396 start(script);
397 }
398 }
399 }
400}
401
406
408{
409 auto& ctx = engine::context();
410 auto& sys = ctx.get_cached<script_system>();
411 auto& ev = ctx.get_cached<events>();
412
413 if(ev.is_playing && sys.is_create_called())
414 {
416
417 if(get_owner().all_of<active_component>())
418 {
419 enable(script_obj, false);
420 }
421 else
422 {
423 disable(script_obj, false);
424 }
425 }
426}
427
428
430{
431 auto obj = type.new_instance();
432 return add_script_component(obj);
433}
434
435auto script_component::add_script_component(const mono::mono_object& obj) -> script_object
436{
437 script_object script_obj(obj);
438 return add_script_component(script_obj);
439}
440
441auto script_component::add_script_component(const script_object& script_obj, bool process_callbacks) -> script_object
442{
443 script_components_.emplace_back(script_obj);
444 script_components_to_create_.emplace_back(script_obj);
445 script_components_to_start_.emplace_back(script_obj);
446
447 auto& obj = script_obj.scoped->object;
448
449 set_entity(obj, get_owner());
450
451 if(process_callbacks)
452 {
453 process_pending_actions(script_obj);
454 }
455
456 return script_obj;
457}
458
460{
461 for(auto& comp : comps)
462 {
463 if(comp.scoped)
464 {
465 add_script_component(comp, false);
466 }
467 }
468}
469
471{
472 for(auto& comp : comps)
473 {
474 if(comp.scoped)
475 {
476 auto& obj = comp.scoped->object;
477 const auto& type = obj.get_type();
478 if(get_script_component(type).scoped)
479 {
480 continue;
481 }
482
484 }
485 }
486}
487
489{
490 auto obj = type.new_instance();
491 auto& script_obj = native_components_.emplace_back(obj);
492
493 set_entity(obj, get_owner());
494
495 return script_obj;
496}
497
498auto script_component::get_script_components(const mono::mono_type& type) -> std::vector<mono::mono_object>
499{
500 std::vector<mono::mono_object> result;
501 for(const auto& component : script_components_)
502 {
503 const auto& comp_type = component.scoped->object.get_type();
504
505 if(comp_type.get_internal_ptr() == type.get_internal_ptr() || comp_type.is_derived_from(type))
506 {
507 result.emplace_back(static_cast<mono::mono_object&>(component.scoped->object));
508 }
509 }
510
511 return result;
512}
513
515{
516 auto it = std::find_if(std::begin(script_components_),
517 std::end(script_components_),
518 [&](const auto& component)
519 {
520 const auto& comp_type = component.scoped->object.get_type();
521 return comp_type.get_internal_ptr() == type.get_internal_ptr() ||
522 comp_type.is_derived_from(type);
523 });
524
525 if(it != std::end(script_components_))
526 {
527 return *it;
528 }
529
530 return {};
531}
532
534{
535 auto it = std::find_if(std::begin(native_components_),
536 std::end(native_components_),
537 [&](const auto& component)
538 {
539 const auto& comp_type = component.scoped->object.get_type();
540 return comp_type.get_internal_ptr() == type.get_internal_ptr() ||
541 comp_type.is_derived_from(type);
542 });
543
544 if(it != std::end(native_components_))
545 {
546 return *it;
547 }
548
549 return {};
550}
551
552auto script_component::remove_script_component(const mono::mono_object& obj) -> bool
553{
554 auto checker = [&](const auto& rhs)
555 {
556 return rhs.scoped->object.get_internal_ptr() == obj.get_internal_ptr();
557 };
558 std::erase_if(script_components_to_create_, checker);
559
560 std::erase_if(script_components_to_start_, checker);
561
562 auto it = std::find_if(std::begin(script_components_), std::end(script_components_), checker);
563
564 if(it != std::end(script_components_))
565 {
566 auto& script_obj = *it;
567
568 set_entity(obj, {});
569
570 script_obj.state->marked_for_destroy = true;
571 return true;
572 }
573
574 return false;
575}
576
577auto script_component::remove_script_component(const mono::mono_type& type) -> bool
578{
579 auto checker = [&](const auto& rhs)
580 {
581 return rhs.scoped->object.get_type().get_internal_ptr() == type.get_internal_ptr();
582 };
583 std::erase_if(script_components_to_create_, checker);
584
585 std::erase_if(script_components_to_start_, checker);
586
587 auto it = std::find_if(std::begin(script_components_), std::end(script_components_), checker);
588
589 if(it != std::end(script_components_))
590 {
591 auto& script_obj = *it;
592 auto& obj = script_obj.scoped->object;
593 set_entity(obj, {});
594
595 script_obj.state->marked_for_destroy = true;
596 return true;
597 }
598
599 return false;
600}
601
602auto script_component::remove_native_component(const mono::mono_object& obj) -> bool
603{
604 auto it = std::find_if(std::begin(native_components_),
605 std::end(native_components_),
606 [&](const auto& rhs)
607 {
608 return rhs.scoped->object.get_internal_ptr() == obj.get_internal_ptr();
609 });
610
611 if(it != std::end(native_components_))
612 {
613 auto& script_obj = *it;
614
615 set_entity(obj, {});
616
617 script_obj.state->marked_for_destroy = true;
618 return true;
619 }
620
621 return false;
622}
623
624auto script_component::remove_native_component(const mono::mono_type& type) -> bool
625{
626 auto it = std::find_if(std::begin(native_components_),
627 std::end(native_components_),
628 [&](const auto& rhs)
629 {
630 return rhs.scoped->object.get_type().get_internal_ptr() == type.get_internal_ptr();
631 });
632
633 if(it != std::end(native_components_))
634 {
635 auto& script_obj = *it;
636
637 auto& obj = script_obj.scoped->object;
638 set_entity(obj, {});
639
640 script_obj.state->marked_for_destroy = true;
641 return true;
642 }
643
644 return false;
645}
646
648{
649 return script_components_;
650}
651
653{
654 return !script_components_.empty();
655}
656
657auto script_component::has_script_components(const std::string& type_name) const -> bool
658{
659 return std::any_of(std::begin(script_components_), std::end(script_components_), [&](const auto& component)
660 {
661 return component.scoped->object.get_type().get_name() == type_name;
662 });
663}
664
666{
667 if(!obj.scoped)
668 {
669 return {};
670 }
671
672 const auto& object = obj.scoped->object;
673 const auto& type = object.get_type();
674 try
675 {
676 auto attrs = type.get_attributes();
677 for(auto& attr : attrs)
678 {
679 if(attr.get_type().get_fullname() == "Unravel.Core.ScriptSourceFileAttribute")
680 {
681 auto invoker = mono::make_property_invoker<std::string>(attr.get_type(), "Path");
682 return invoker.get_value(attr);
683 }
684 }
685 auto prop = type.get_property("SourceFilePath");
686 auto invoker = mono::make_property_invoker<std::string>(prop);
687 return invoker.get_value(object);
688 }
689 catch(const mono::mono_exception& e)
690 {
691 return {};
692 }
693}
694} // 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:115
auto is_create_called() const -> bool
static void log_exception(const mono::mono_exception &e, const hpp::source_location &loc=hpp::source_location::current())