feo_oop_engine/scripting/
executor.rs

1//! \[backend\] Manages the async scripts.
2use {
3    super::{
4        swap::Swap,
5        globals::EngineGlobals,
6    },
7    crate::{
8        scene::{
9            Scene,
10            game_object::GameObject,
11        },
12        registration::{
13            relation::{
14                Parent, 
15                ParentWrapper
16            },
17            id::ID,
18        }
19    },
20    std::{
21        future::Future,
22        sync::mpsc::{
23            Receiver,
24            SyncSender
25        },
26        collections::HashMap,
27        sync::{
28            Arc,
29            Mutex, 
30            RwLock
31        },
32        task::{
33            Context, 
34            Poll
35        }
36    },
37    futures::{
38        future::{
39            BoxFuture, 
40            FutureExt
41        },
42        task::{
43            waker_ref,
44            ArcWake
45        },
46    },
47    rayon::slice::ParallelSliceMut,
48};
49
50pub struct Executor {
51    pub ready: Vec<Arc<RwLock<Box<dyn GameObject>>>>,
52    pub queue: Receiver<Arc<Task>>,
53}
54
55#[derive(Clone)]
56pub struct Spawner {
57    pub engine_globals: EngineGlobals, // distributed to all frames
58    pub task_sender: SyncSender<Arc<Task>>,
59}
60
61pub struct Task{
62    future: Mutex<Option<BoxFuture<'static, Swap>>>,
63    task_sender: SyncSender<Arc<Task>>,
64}
65
66impl Spawner {
67    pub fn spawn(&self, future: impl Future<Output = Swap> + 'static + Send) {
68        let future = future.boxed();
69        let task = Arc::new(Task {
70            future: Mutex::new(Some(future)),
71            task_sender: self.task_sender.clone(),
72        });
73        self.task_sender.send(task).expect("too many tasks queued");
74    }
75}
76
77impl ArcWake for Task {
78    fn wake_by_ref(arc_self: &Arc<Self>) {
79        let cloned = arc_self.clone();
80        arc_self
81            .task_sender
82            .send(cloned)
83            .expect("too many tasks queued");
84    }
85}
86
87impl Executor {
88    pub fn run(&self, scene: Arc<RwLock<Scene>>) {
89        let mut swaps = Vec::new();
90        
91        while let Ok(task) = self.queue.recv() {
92            let mut future_slot = task.future.lock().unwrap();
93            if let Some(mut future) = future_slot.take() {
94                let waker = waker_ref(&task);
95                let context = &mut Context::from_waker(&*waker);
96                match future.as_mut().poll(context) {
97                    Poll::Pending => { *future_slot = Some(future); },
98                    Poll::Ready(swap_status) => {
99                        match swap_status {
100                            Swap::None => {},
101                            _ => { swaps.push(swap_status); }
102                        }
103                    },
104                }
105            }
106        }
107
108        if !swaps.is_empty() {
109            Self::sort(&mut swaps, scene.clone());
110
111            swaps.into_iter().for_each( |swap| {
112                match swap {
113                    // By swapping out the physical pointers rather than the interior it makes it possible to store a pointer to swap back in later
114                    Swap::SwapParent(id, replacement) => { //
115                        let mut found = false;
116                        let mut queue = scene.read().unwrap().get_children().clone();
117                        
118                        while let (Some(old), false) = (queue.pop(), found) {
119                            let read = old.read().unwrap(); // will not actually be changing the target object
120                            queue.append(&mut read.get_children());
121                            if read.get_id() == id {
122                                let children = read.get_children();
123                                let parent = read.get_parent();
124    
125                                // direct children to the replacement
126                                children.into_iter().for_each(|child| {
127                                    // set child object's parent object to be the new object
128                                    unsafe { child.write().unwrap().set_parent(ParentWrapper::GameObject(replacement.clone()))};
129                                    
130                                    // set replacement's child objects to be the new object
131                                    replacement.write().unwrap().add_child(child);
132                                });
133    
134                                // direct parent to the replacement
135                                match parent.clone() { // shadowing
136                                    ParentWrapper::GameObject(parent) => unsafe { 
137                                        parent.write().unwrap().replace_child(old.clone(), replacement.clone()).unwrap();
138                                    },
139                                    ParentWrapper::Scene(p) => unsafe {
140                                        p.write().unwrap().replace_child(old.clone(), replacement.clone()).unwrap();
141                                    }
142                                }
143                                unsafe { replacement.write().unwrap().set_parent(parent); }
144    
145                                found = true;
146                            }
147                        }
148                        
149                        // Check Camera
150                        let mut scene_rw = scene.write().unwrap();
151                        if let Some(old_camera) = scene_rw.main_camera.clone() {
152                            let old_camera_read = old_camera.read().unwrap();
153                            if id == old_camera_read.get_id() { 
154                                
155                                // Note that swapping a main camera parent does not make sense unless the main camera is part of the game_object tree since those objects would not be drawn.
156                                // If your intent is to toggle this group the objects and toggle their visibility attribute instead.
157                                assert!(found);
158                                // // direct children to the replacement
159                                // let children = old_camera_read.get_children();
160                                // let parent = old_camera_read.get_parent();
161                                // let as_gameobject = old_camera_read.cast_gameobject_arc_rwlock(old_camera.clone());
162                                // children.into_iter().for_each(|child| {
163                                //     // set child object's parent object to be the new object
164                                //     unsafe { child.write().unwrap().set_parent(ParentWrapper::GameObject(replacement.clone())) };
165                                //     // set replacement's child objects to be the new object
166                                //     replacement.write().unwrap().add_child(child);
167                                // });
168    
169                                // // direct parent to the replacement
170                                // match parent.clone() {
171                                //     ParentWrapper::GameObject(p) => unsafe { 
172                                //         p.write().unwrap().replace_child(as_gameobject.clone(), replacement.clone()).unwrap();
173                                //     },
174                                //     ParentWrapper::Scene(_) => unsafe { 
175                                //         scene_rw.replace_child(as_gameobject, replacement.clone()).unwrap();
176                                //     },
177                                // }
178                                // unsafe { replacement.write().unwrap().set_parent(parent); }
179    
180                                // replace the old camera with the replacement in the main_camera slot
181                                scene_rw.main_camera = Some(replacement.clone().read().unwrap().cast_camera_arc_rwlock(replacement.clone()).unwrap()); 
182    
183                                found = true;
184                            }
185                        }
186                        
187                        if !found {
188                            panic!("could not find the ID.");
189                        } 
190                    },
191                    // cutting is fine here
192                    Swap::SwapFull(id, replacement) => {
193                        let mut found = false;
194                        let mut queue = scene.read().unwrap().get_children().clone();
195                        
196                        while let (Some(old), false) = (queue.pop(), found) {
197                            let read = old.read().unwrap(); // will not actually be changing the target object
198                            queue.append(&mut read.get_children());
199                            if read.get_id() == id {
200                                let parent = read.get_parent();
201    
202                                // direct parent to the replacement
203                                match parent.clone() { // shadowing
204                                    ParentWrapper::GameObject(parent) => unsafe { 
205                                        parent.write().unwrap().replace_child(old.clone(), replacement.clone()).unwrap();
206                                    },
207                                    ParentWrapper::Scene(p) => unsafe {
208                                        p.write().unwrap().replace_child(old.clone(), replacement.clone()).unwrap();
209                                    }
210                                }
211                                unsafe { replacement.write().unwrap().set_parent(parent); }
212    
213                                found = true;
214                            }
215                        }
216                        
217                        // Check Camera
218                        let mut scene_rw = scene.write().unwrap();
219                        if let Some(old_camera) = scene_rw.main_camera.clone() {
220                            let old_camera_read = old_camera.read().unwrap();
221                            if id == old_camera_read.get_id() {
222                                let parent = old_camera_read.get_parent();
223                                // Not needed because It is done in above loop based on children of parents
224                                // let as_gameobject = old_camera_read.cast_gameobject_arc_rwlock(old_camera.clone());
225                                // match parent.clone() {
226                                //     ParentWrapper::GameObject(p) => unsafe { 
227                                //         p.write().unwrap().replace_child(as_gameobject.clone(), replacement.clone()).unwrap();
228                                //     },
229                                //     ParentWrapper::Scene(_) => unsafe { 
230                                //         scene_rw.replace_child(as_gameobject.clone(), replacement.clone()).unwrap();
231                                //     },
232                                // }
233
234                                // needed in the case that someone does not wish to have scripts on a main camera with scene parent and thus does not 
235                                // tell parent that camera is its child.
236                                unsafe { replacement.write().unwrap().set_parent(parent); }
237
238                                scene_rw.main_camera = Some(replacement.clone().read().unwrap().cast_camera_arc_rwlock(replacement.clone()).unwrap()); 
239
240                                found = true;
241                            }
242                        }
243                        
244                        if !found {
245                            panic!("could not find the ID.");
246                        } 
247                    },
248                   
249                    Swap::Delete(id) => {
250                        let mut found = false;
251                        let mut queue = scene.read().unwrap().get_children().clone();
252                        while let Some(old) = queue.pop() {
253                            let read = old.read().unwrap(); // will not actually be changing the target object
254                            queue.append(&mut read.get_children());
255                            if read.get_id() == id {
256                                let parent = read.get_parent();
257    
258                                // direct parent to the replacement
259                                match parent.clone() { // shadowing
260                                    ParentWrapper::GameObject(p) => unsafe { 
261                                        p.write().unwrap().remove_child(old.clone()).unwrap();
262                                    },
263                                    ParentWrapper::Scene(p) => unsafe {
264                                        p.write().unwrap().remove_child(old.clone()).unwrap();
265                                    }
266                                }
267    
268                                found = true;
269                            }
270                        }
271                        
272                        // Check Camera
273                        if let Some(camera) = scene.read().unwrap().main_camera.clone() {
274                            if id == camera.read().expect("camera in use").get_id() { 
275                                panic!("You can not delete the main camera. It can only be replaced.");
276                            }
277                        }
278                        
279                        if !found {
280                            panic!("could not find the ID.");
281                        } 
282                    },
283                    _ => { panic!("not possible"); }
284                }
285            });
286        }
287    }
288
289    #[inline(always)]
290    fn order_id(game_object: Arc<RwLock<dyn GameObject>>, n: &mut usize) -> Vec<(ID, usize)>{
291        let read_lock = game_object.read().unwrap();
292        let mut result: Vec<(ID, usize)> = vec![(read_lock.get_id(), *n)];
293        read_lock.get_children().into_iter().for_each(|child| {
294            *n -= 1;
295            result.append(&mut Self::order_id(child, n));
296        });
297        result
298    }
299
300    fn sort(swaps: &mut Vec<Swap>, scene: Arc<RwLock<Scene>>) {
301        let read_lock = scene.read().unwrap();
302        
303        // sort by parent, children... , parent2, children2...
304        let mut order: Vec<(ID, usize)> = Vec::new();
305
306        // reverse to get  ...children2, parent2, ...children, parent
307        let mut n = usize::MAX;
308        read_lock.get_children().into_iter().for_each(|child| {
309            order.append(&mut Self::order_id(child, &mut n));
310        });
311
312        let hash_map: HashMap<ID, usize> = order.into_iter().collect();
313
314        swaps.par_sort_unstable_by_key(|swap| hash_map.get(swap.get_id().unwrap()));
315    }
316}