1extern crate oxygengine_core as core;
2
3use core::{
4 app::AppBuilder,
5 ecs::{
6 commands::{SpawnEntity, UniverseCommands},
7 components::Name,
8 hierarchy::{Hierarchy, Parent},
9 pipeline::{PipelineBuilder, PipelineBuilderError},
10 Component, Entity, EntityBuilder, Query, Universe, World,
11 },
12 scripting::{
13 intuicio::{core::prelude::*, data::prelude::*},
14 ScriptFunctionReference, Scripting,
15 },
16};
17use std::borrow::Cow;
18
19const DEFAULT_CAPACITY: usize = 10240;
20
21#[derive(Default, Clone)]
22pub struct ScriptedNodeEntity(AsyncShared<Option<Entity>>);
23
24impl ScriptedNodeEntity {
25 pub fn new(entity: Entity) -> Self {
26 Self(AsyncShared::new(Some(entity)))
27 }
28
29 pub fn find(path: &str, hierarchy: &Hierarchy) -> Self {
30 if let Some(entity) = hierarchy.entity_by_name(path) {
31 Self::new(entity)
32 } else {
33 Self::default()
34 }
35 }
36
37 pub fn find_raw(path: &str, hierarchy: &Hierarchy) -> Option<Entity> {
38 hierarchy.entity_by_name(path)
39 }
40
41 pub fn find_all_of_type<T: 'static>(world: &World) -> Vec<Self> {
42 world
43 .query::<&ScriptedNode>()
44 .iter()
45 .filter_map(move |(entity, node)| {
46 if node.is::<T>() {
47 Some(Self::new(entity))
48 } else {
49 None
50 }
51 })
52 .collect()
53 }
54
55 pub fn find_all_of_type_raw<T: 'static>(world: &World) -> Vec<Entity> {
56 world
57 .query::<&ScriptedNode>()
58 .iter()
59 .filter_map(
60 move |(entity, node)| {
61 if node.is::<T>() {
62 Some(entity)
63 } else {
64 None
65 }
66 },
67 )
68 .collect()
69 }
70
71 pub fn set(&mut self, entity: Entity) {
72 if let Some(mut data) = self.0.write() {
73 *data = Some(entity);
74 }
75 }
76
77 pub fn get(&self) -> Option<Entity> {
78 self.0.read().and_then(|data| data.as_ref().copied())
79 }
80
81 pub fn is_valid(&self) -> bool {
82 self.0.read().map(|data| data.is_some()).unwrap_or_default()
83 }
84
85 pub fn take(&mut self) -> Option<Entity> {
86 self.0.write().and_then(|mut data| data.take())
87 }
88
89 pub fn node<Q: Query, R>(
90 &self,
91 world: &World,
92 mut f: impl FnMut(&ScriptedNode, Q::Item<'_>) -> R,
93 ) -> Option<R> {
94 let entity = *self.0.read()?.as_ref()?;
95 let mut query = world.query_one::<(&ScriptedNode, Q)>(entity).ok()?;
96 let (node, query) = query.get()?;
97 Some(f(node, query))
98 }
99
100 pub fn node_mut<Q: Query, R>(
101 &self,
102 world: &World,
103 mut f: impl FnMut(&mut ScriptedNode, Q::Item<'_>) -> R,
104 ) -> Option<R> {
105 let entity = *self.0.read()?.as_ref()?;
106 let mut query = world.query_one::<(&mut ScriptedNode, Q)>(entity).ok()?;
107 let (node, query) = query.get()?;
108 Some(f(node, query))
109 }
110
111 pub fn with<T: 'static, Q: Query, R>(
112 &self,
113 world: &World,
114 mut f: impl FnMut(&T, Q::Item<'_>) -> R,
115 ) -> Option<R> {
116 let entity = *self.0.read()?.as_ref()?;
117 let mut query = world.query_one::<(&ScriptedNode, Q)>(entity).ok()?;
118 let (node, query) = query.get()?;
119 let node = node.read::<T>()?;
120 Some(f(&node, query))
121 }
122
123 pub fn with_mut<T: 'static, Q: Query, R>(
124 &self,
125 world: &World,
126 mut f: impl FnMut(&mut T, Q::Item<'_>) -> R,
127 ) -> Option<R> {
128 let entity = *self.0.read()?.as_ref()?;
129 let mut query = world.query_one::<(&mut ScriptedNode, Q)>(entity).ok()?;
130 let (node, query) = query.get()?;
131 let mut node = node.write::<T>()?;
132 Some(f(&mut node, query))
133 }
134}
135
136impl std::fmt::Debug for ScriptedNodeEntity {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 let mut result = f.debug_struct("ScriptedNodeEntity");
139 match self.get() {
140 Some(entity) => result.field("entity", &entity).finish(),
141 None => result.finish_non_exhaustive(),
142 }
143 }
144}
145
146pub enum ScriptedNodesParam {
147 Owned(DynamicManaged),
148 Ref(DynamicManagedRef),
149 RefMut(DynamicManagedRefMut),
150 ScopedRef(DynamicManagedRef, Lifetime),
151 ScopedRefMut(DynamicManagedRefMut, Lifetime),
152}
153
154impl ScriptedNodesParam {
155 pub fn owned<T: 'static>(value: T) -> Self {
156 Self::Owned(DynamicManaged::new(value))
157 }
158
159 pub fn scoped_ref<'a, T: 'static>(value: &'a T) -> Self
160 where
161 Self: 'a,
162 {
163 let lifetime = Lifetime::default();
164 let data = DynamicManagedRef::new(value, lifetime.borrow().unwrap());
165 Self::ScopedRef(data, lifetime)
166 }
167
168 pub fn scoped_ref_mut<'a, T: 'static>(value: &'a mut T) -> Self
169 where
170 Self: 'a,
171 {
172 let lifetime = Lifetime::default();
173 let data = DynamicManagedRefMut::new(value, lifetime.borrow_mut().unwrap());
174 Self::ScopedRefMut(data, lifetime)
175 }
176}
177
178impl From<DynamicManaged> for ScriptedNodesParam {
179 fn from(value: DynamicManaged) -> Self {
180 Self::Owned(value)
181 }
182}
183
184impl From<DynamicManagedRef> for ScriptedNodesParam {
185 fn from(value: DynamicManagedRef) -> Self {
186 Self::Ref(value)
187 }
188}
189
190impl From<DynamicManagedRefMut> for ScriptedNodesParam {
191 fn from(value: DynamicManagedRefMut) -> Self {
192 Self::RefMut(value)
193 }
194}
195
196impl<T: 'static> From<&T> for ScriptedNodesParam {
197 fn from(value: &T) -> Self {
198 Self::scoped_ref(value)
199 }
200}
201
202impl<T: 'static> From<&mut T> for ScriptedNodesParam {
203 fn from(value: &mut T) -> Self {
204 Self::scoped_ref_mut(value)
205 }
206}
207
208pub struct ScriptedNode {
209 pub active: bool,
210 pub object: DynamicManaged,
211}
212
213impl ScriptedNode {
214 pub fn new<T: 'static>(data: T) -> Self {
215 Self::new_raw(DynamicManaged::new(data))
216 }
217
218 pub fn new_raw(object: DynamicManaged) -> Self {
219 Self {
220 active: true,
221 object,
222 }
223 }
224
225 pub fn with_active(mut self, value: bool) -> Self {
226 self.active = value;
227 self
228 }
229
230 pub fn is<T: 'static>(&self) -> bool {
231 self.object.is::<T>()
232 }
233
234 pub fn read<T: 'static>(&self) -> Option<ValueReadAccess<T>> {
235 self.object.read::<T>()
236 }
237
238 pub fn write<T: 'static>(&mut self) -> Option<ValueWriteAccess<T>> {
239 self.object.write::<T>()
240 }
241}
242
243pub struct ScriptedNodeSignal {
244 entity: Option<Entity>,
245 function: ScriptFunctionReference,
246 arguments: Vec<ScriptedNodesParam>,
247 broadcast: bool,
248 bubble: bool,
249 ignore_me: bool,
250}
251
252impl ScriptedNodeSignal {
253 pub fn parse(entity: Option<Entity>, content: &str) -> Result<Self, String> {
254 Ok(Self::new(entity, ScriptFunctionReference::parse(content)?))
255 }
256
257 pub fn new(entity: Option<Entity>, function: ScriptFunctionReference) -> Self {
258 Self {
259 entity,
260 function,
261 arguments: Default::default(),
262 broadcast: false,
263 bubble: false,
264 ignore_me: false,
265 }
266 }
267
268 pub fn arg(mut self, data: impl Into<ScriptedNodesParam>) -> Self {
269 self.arguments.push(data.into());
270 self
271 }
272
273 pub fn broadcast(mut self) -> Self {
274 self.broadcast = true;
275 self
276 }
277
278 pub fn bubble(mut self) -> Self {
279 self.bubble = true;
280 self
281 }
282
283 pub fn ignore_me(mut self) -> Self {
284 self.ignore_me = true;
285 self
286 }
287
288 pub fn dispatch<T: ScriptedNodeComponentPack>(&self, universe: &Universe) {
289 let world = universe.world();
290 let mut nodes = universe.expect_resource_mut::<ScriptedNodes>();
291 let scripting = universe.expect_resource::<Scripting>();
292 let hierarchy = universe.expect_resource::<Hierarchy>();
293
294 if let Some(entity) = self.entity {
295 Self::execute::<T>(
296 entity,
297 &self.function,
298 &self.arguments,
299 self.broadcast,
300 self.bubble,
301 self.ignore_me,
302 &world,
303 &mut nodes,
304 &scripting,
305 &hierarchy,
306 );
307 } else {
308 for (entity, _) in world
309 .query::<()>()
310 .with::<&ScriptedNode>()
311 .without::<&Parent>()
312 .iter()
313 {
314 Self::execute::<T>(
315 entity,
316 &self.function,
317 &self.arguments,
318 self.broadcast,
319 self.bubble,
320 self.ignore_me,
321 &world,
322 &mut nodes,
323 &scripting,
324 &hierarchy,
325 );
326 }
327 }
328 }
329
330 #[allow(clippy::too_many_arguments)]
331 pub fn execute<T: ScriptedNodeComponentPack>(
332 entity: Entity,
333 function_ref: &ScriptFunctionReference,
334 args: &[ScriptedNodesParam],
335 broadcast: bool,
336 bubble: bool,
337 ignore_me: bool,
338 world: &World,
339 nodes: &mut ScriptedNodes,
340 scripting: &Scripting,
341 hierarchy: &Hierarchy,
342 ) {
343 let token = nodes.context.stack().store();
344 let result = if !ignore_me {
345 if let Ok(mut query) = world.query_one::<(&mut ScriptedNode, T)>(entity) {
346 if let Some((node, pack)) = query.get() {
347 let mut query = function_ref.query();
348 if query.struct_query.is_none() {
349 query.struct_query = Some(StructQuery {
350 type_hash: Some(*node.object.type_hash()),
351 ..Default::default()
352 });
353 }
354 if let Some(function) = scripting.registry.find_function(query) {
355 if let Some(handle) = &function.signature().struct_handle {
356 if node.object.type_hash() != &handle.type_hash() {
357 return;
358 }
359 }
360 nodes.context.stack().push(DynamicManaged::new(entity));
361 let mut compontents_params = vec![];
362 T::query_param(pack, &mut compontents_params);
363 for arg in compontents_params.iter().chain(args.iter()).rev() {
364 match arg {
365 ScriptedNodesParam::Owned(arg) => {
366 nodes.context.stack().push(arg.borrow().unwrap());
367 }
368 ScriptedNodesParam::Ref(arg) => {
369 nodes.context.stack().push(arg.borrow().unwrap());
370 }
371 ScriptedNodesParam::RefMut(arg) => {
372 nodes.context.stack().push(arg.borrow_mut().unwrap());
373 }
374 ScriptedNodesParam::ScopedRef(arg, _) => {
375 nodes.context.stack().push(arg.borrow().unwrap());
376 }
377 ScriptedNodesParam::ScopedRefMut(arg, _) => {
378 nodes.context.stack().push(arg.borrow_mut().unwrap());
379 }
380 }
381 }
382 nodes
383 .context
384 .stack()
385 .push(node.object.borrow_mut().unwrap());
386 Some((function, compontents_params))
387 } else {
388 None
389 }
390 } else {
391 None
392 }
393 } else {
394 None
395 }
396 } else {
397 None
398 };
399 if let Some((function, _)) = result {
400 function.invoke(&mut nodes.context, &scripting.registry);
401 }
402 nodes.context.stack().restore(token);
403 if broadcast {
404 if let Some(iter) = hierarchy.children(entity) {
405 for entity in iter {
406 Self::execute::<T>(
407 entity,
408 function_ref,
409 args,
410 true,
411 false,
412 false,
413 world,
414 nodes,
415 scripting,
416 hierarchy,
417 );
418 }
419 }
420 }
421 if bubble {
422 if let Some(entity) = hierarchy.parent(entity) {
423 Self::execute::<T>(
424 entity,
425 function_ref,
426 args,
427 false,
428 true,
429 false,
430 world,
431 nodes,
432 scripting,
433 hierarchy,
434 );
435 }
436 }
437 }
438}
439
440#[derive(Default)]
441pub struct ScriptedNodesSpawns {
442 spawns: Vec<(ScriptedNodesTree, Option<Entity>)>,
443}
444
445impl ScriptedNodesSpawns {
446 pub fn spawn(&mut self, tree: ScriptedNodesTree, parent: Option<Entity>) {
447 self.spawns.push((tree, parent));
448 }
449
450 pub fn spawn_root(&mut self, tree: ScriptedNodesTree) {
451 self.spawn(tree, None)
452 }
453}
454
455#[derive(Default)]
456pub struct ScriptedNodesSignals {
457 #[allow(clippy::type_complexity)]
458 signals: Vec<Box<dyn FnOnce(&Universe) + Send + Sync>>,
459}
460
461impl ScriptedNodesSignals {
462 pub fn signal<T: ScriptedNodeComponentPack>(&mut self, signal: ScriptedNodeSignal) {
463 self.signals
464 .push(Box::new(move |universe| signal.dispatch::<T>(universe)));
465 }
466}
467
468pub struct ScriptedNodes {
469 context: Context,
470}
471
472impl Default for ScriptedNodes {
473 fn default() -> Self {
474 Self::new(DEFAULT_CAPACITY, DEFAULT_CAPACITY, DEFAULT_CAPACITY)
475 }
476}
477
478impl ScriptedNodes {
479 pub fn new(
480 stack_capacity: usize,
481 registers_capacity: usize,
482 heap_page_capacity: usize,
483 ) -> Self {
484 Self {
485 context: Context::new(stack_capacity, registers_capacity, heap_page_capacity),
486 }
487 }
488
489 pub fn maintain(universe: &Universe) {
490 {
491 let mut signals = universe.expect_resource_mut::<ScriptedNodesSignals>();
492 for signal in std::mem::take(&mut signals.signals) {
493 signal(universe);
494 }
495 }
496 {
497 let mut commands = universe.expect_resource_mut::<UniverseCommands>();
498 let mut spawns = universe.expect_resource_mut::<ScriptedNodesSpawns>();
499 for (tree, parent) in std::mem::take(&mut spawns.spawns) {
500 Self::execute_spawn(tree, parent, &mut commands);
501 }
502 }
503 }
504
505 fn execute_spawn(
506 tree: ScriptedNodesTree,
507 parent: Option<Entity>,
508 commands: &mut UniverseCommands,
509 ) {
510 let ScriptedNodesTree {
511 active,
512 object,
513 children,
514 mut components,
515 setup,
516 bind,
517 } = tree;
518 if let Some(entity) = parent {
519 components.add(Parent(entity));
520 }
521 components.add(ScriptedNode { active, object });
522 commands.schedule(
523 SpawnEntity::new(components).on_complete(move |universe, entity| {
524 if let Some(function) = setup {
525 let mut signals = universe.expect_resource_mut::<ScriptedNodesSignals>();
526 signals.signal::<()>(ScriptedNodeSignal::new(Some(entity), function));
527 }
528 if let Some(bind) = bind {
529 (bind)(entity);
530 }
531 let mut commands = universe.expect_resource_mut::<UniverseCommands>();
532 for child in children {
533 Self::execute_spawn((child)(), Some(entity), &mut commands);
534 }
535 }),
536 );
537 }
538
539 pub fn dispatch<T: ScriptedNodeComponentPack>(
540 &mut self,
541 universe: &Universe,
542 function: ScriptFunctionReference,
543 args: &[ScriptedNodesParam],
544 ) {
545 let world = universe.world();
546 let scripting = universe.expect_resource::<Scripting>();
547 let hierarchy = universe.expect_resource::<Hierarchy>();
548
549 for (entity, _) in world
550 .query::<()>()
551 .with::<&ScriptedNode>()
552 .without::<&Parent>()
553 .iter()
554 {
555 self.execute::<T>(entity, &function, args, &world, &scripting, &hierarchy);
556 }
557 }
558
559 pub fn execute<T: ScriptedNodeComponentPack>(
560 &mut self,
561 entity: Entity,
562 function_ref: &ScriptFunctionReference,
563 args: &[ScriptedNodesParam],
564 world: &World,
565 scripting: &Scripting,
566 hierarchy: &Hierarchy,
567 ) {
568 if let Ok(mut query) = world.query_one::<&ScriptedNode>(entity) {
569 if let Some(node) = query.get() {
570 if !node.active {
571 return;
572 }
573 }
574 }
575 let token = self.context.stack().store();
576 let result = if let Ok(mut query) = world.query_one::<(&mut ScriptedNode, T)>(entity) {
577 if let Some((node, pack)) = query.get() {
578 let mut query = function_ref.query();
579 if query.struct_query.is_none() {
580 query.struct_query = Some(StructQuery {
581 type_hash: Some(*node.object.type_hash()),
582 ..Default::default()
583 });
584 }
585 if let Some(function) = scripting.registry.find_function(query) {
586 if let Some(handle) = &function.signature().struct_handle {
587 if node.object.type_hash() != &handle.type_hash() {
588 return;
589 }
590 }
591 self.context.stack().push(DynamicManaged::new(entity));
592 let mut compontents_params = vec![];
593 T::query_param(pack, &mut compontents_params);
594 for arg in compontents_params.iter().chain(args.iter()).rev() {
595 match arg {
596 ScriptedNodesParam::Owned(arg) => {
597 self.context.stack().push(arg.borrow().unwrap());
598 }
599 ScriptedNodesParam::Ref(arg) => {
600 self.context.stack().push(arg.borrow().unwrap());
601 }
602 ScriptedNodesParam::RefMut(arg) => {
603 self.context.stack().push(arg.borrow_mut().unwrap());
604 }
605 ScriptedNodesParam::ScopedRef(arg, _) => {
606 self.context.stack().push(arg.borrow().unwrap());
607 }
608 ScriptedNodesParam::ScopedRefMut(arg, _) => {
609 self.context.stack().push(arg.borrow_mut().unwrap());
610 }
611 }
612 }
613 self.context.stack().push(node.object.borrow_mut().unwrap());
614 Some((function, compontents_params))
615 } else {
616 None
617 }
618 } else {
619 None
620 }
621 } else {
622 None
623 };
624 if let Some((function, _)) = result {
625 function.invoke(&mut self.context, &scripting.registry);
626 }
627 self.context.stack().restore(token);
628 if let Some(iter) = hierarchy.children(entity) {
629 for entity in iter {
630 self.execute::<T>(entity, function_ref, args, world, scripting, hierarchy);
631 }
632 }
633 }
634}
635
636pub struct ScriptedNodesTree {
637 active: bool,
638 object: DynamicManaged,
639 components: EntityBuilder,
640 children: Vec<Box<dyn FnOnce() -> Self + Send + Sync>>,
641 setup: Option<ScriptFunctionReference>,
642 bind: Option<Box<dyn FnOnce(Entity) + Send + Sync>>,
643}
644
645impl ScriptedNodesTree {
646 pub fn empty() -> Self {
647 Self::new(())
648 }
649
650 pub fn new<T: 'static>(data: T) -> Self {
651 Self::new_raw(DynamicManaged::new(data))
652 }
653
654 pub fn new_raw(object: DynamicManaged) -> Self {
655 Self {
656 active: true,
657 object,
658 children: Default::default(),
659 components: Default::default(),
660 setup: None,
661 bind: None,
662 }
663 }
664
665 pub fn name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
666 self.components.add(Name(name.into()));
667 self
668 }
669
670 pub fn inactive(mut self) -> Self {
671 self.active = false;
672 self
673 }
674
675 pub fn component<T: Component>(mut self, component: T) -> Self {
676 self.components.add(component);
677 self
678 }
679
680 pub fn child(mut self, f: impl FnOnce() -> Self + Send + Sync + 'static) -> Self {
681 self.children.push(Box::new(f));
682 self
683 }
684
685 pub fn setup(mut self, function: ScriptFunctionReference) -> Self {
686 self.setup = Some(function);
687 self
688 }
689
690 pub fn bind(mut self, f: impl FnOnce(Entity) + Send + Sync + 'static) -> Self {
691 self.bind = Some(Box::new(f));
692 self
693 }
694}
695
696pub trait ScriptedNodeComponentPack: Query {
697 fn query_param(pack: Self::Item<'_>, list: &mut Vec<ScriptedNodesParam>);
698}
699
700impl ScriptedNodeComponentPack for () {
701 fn query_param(_: (), _: &mut Vec<ScriptedNodesParam>) {}
702}
703
704impl<T: Component> ScriptedNodeComponentPack for &T {
705 fn query_param(pack: Self::Item<'_>, list: &mut Vec<ScriptedNodesParam>) {
706 list.push(ScriptedNodesParam::scoped_ref(pack));
707 }
708}
709
710impl<T: Component> ScriptedNodeComponentPack for &mut T {
711 fn query_param(pack: Self::Item<'_>, list: &mut Vec<ScriptedNodesParam>) {
712 list.push(ScriptedNodesParam::scoped_ref_mut(pack));
713 }
714}
715
716macro_rules! impl_component_tuple {
717 ($($type:ident),+) => {
718 impl<$($type: ScriptedNodeComponentPack),+> ScriptedNodeComponentPack for ($($type,)+) {
719 fn query_param(pack: Self::Item<'_>, list: &mut Vec<ScriptedNodesParam>) {
720 #[allow(non_snake_case)]
721 let ( $($type,)+ ) = pack;
722 $(
723 $type::query_param($type, list);
724 )+
725 }
726 }
727 };
728}
729
730impl_component_tuple!(A);
731impl_component_tuple!(A, B);
732impl_component_tuple!(A, B, C);
733impl_component_tuple!(A, B, C, D);
734impl_component_tuple!(A, B, C, D, E);
735impl_component_tuple!(A, B, C, D, E, F);
736impl_component_tuple!(A, B, C, D, E, F, G);
737impl_component_tuple!(A, B, C, D, E, F, G, H);
738impl_component_tuple!(A, B, C, D, E, F, G, H, I);
739impl_component_tuple!(A, B, C, D, E, F, G, H, I, J);
740impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K);
741impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
742impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
743impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
744impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
745
746pub fn bundle_installer<PB>(
747 builder: &mut AppBuilder<PB>,
748 nodes: ScriptedNodes,
749) -> Result<(), PipelineBuilderError>
750where
751 PB: PipelineBuilder,
752{
753 builder.install_resource(nodes);
754 builder.install_resource(ScriptedNodesSpawns::default());
755 builder.install_resource(ScriptedNodesSignals::default());
756 Ok(())
757}