1pub mod commands;
2pub mod components;
3pub mod hierarchy;
4pub mod life_cycle;
5pub mod pipeline;
6
7use crate::{
8 app::AppLifeCycle,
9 ecs::{
10 commands::UniverseCommands,
11 components::NonPersistent,
12 life_cycle::EntityChanges,
13 pipeline::{PipelineEngine, PipelineId},
14 },
15 state::{State, StateChange, StateToken},
16};
17pub use hecs::*;
18use std::{
19 any::{type_name, Any, TypeId},
20 collections::{HashMap, HashSet},
21 marker::PhantomData,
22 ops::{Deref, DerefMut},
23 sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
24};
25use typid::ID;
26
27pub type System = fn(&mut Universe);
28pub type UniverseId = ID<Universe>;
29pub type Resource = dyn Any + Send + Sync;
30
31pub struct WorldRef;
32pub struct Comp<T>(PhantomData<fn() -> T>);
33
34#[derive(Default)]
35pub struct Multiverse {
36 pub parallel: bool,
37 universes: HashMap<UniverseId, Universe>,
38 pipelines: HashMap<PipelineId, Box<dyn PipelineEngine + Send + Sync>>,
39 bindings: HashMap<UniverseId, PipelineId>,
40 default_universe: Option<UniverseId>,
41}
42
43impl Multiverse {
44 pub fn new<T, S>(pipeline: T, state: S) -> Self
45 where
46 T: PipelineEngine + 'static + Send + Sync,
47 S: State + 'static,
48 {
49 let mut result = Self::default();
50 let universe = result.create_universe(state);
51 let pipeline = result.insert_pipeline(pipeline);
52 result.bind(universe, pipeline);
53 result.set_default_universe_id(Some(universe));
54 result
55 }
56
57 pub fn with_parallel(mut self, mode: bool) -> Self {
58 self.parallel = mode;
59 self
60 }
61
62 pub fn create_universe<S>(&mut self, state: S) -> UniverseId
63 where
64 S: State + 'static,
65 {
66 let id = UniverseId::new();
67 self.universes.insert(id, Universe::new(state));
68 id
69 }
70
71 pub fn delete_universe(&mut self, id: UniverseId) -> Option<Universe> {
72 if let Some(uni) = self.default_universe {
73 if uni == id {
74 self.default_universe = None;
75 }
76 }
77 self.bindings.remove(&id);
78 self.universes.remove(&id)
79 }
80
81 pub fn default_universe_id(&self) -> Option<UniverseId> {
82 self.default_universe
83 }
84
85 pub fn set_default_universe_id(&mut self, id: Option<UniverseId>) {
86 self.default_universe = id;
87 }
88
89 pub fn default_universe(&self) -> Option<&Universe> {
90 if let Some(id) = self.default_universe {
91 self.universe(id)
92 } else {
93 None
94 }
95 }
96
97 pub fn default_universe_mut(&mut self) -> Option<&mut Universe> {
98 if let Some(id) = self.default_universe {
99 self.universe_mut(id)
100 } else {
101 None
102 }
103 }
104
105 pub fn universe(&self, id: UniverseId) -> Option<&Universe> {
106 self.universes.get(&id)
107 }
108
109 pub fn universe_mut(&mut self, id: UniverseId) -> Option<&mut Universe> {
110 self.universes.get_mut(&id)
111 }
112
113 pub fn universe_ids(&self) -> impl Iterator<Item = UniverseId> + '_ {
114 self.universes.keys().cloned()
115 }
116
117 pub fn universes(&self) -> impl Iterator<Item = &Universe> {
118 self.universes.values()
119 }
120
121 pub fn universes_mut(&mut self) -> impl Iterator<Item = &mut Universe> {
122 self.universes.values_mut()
123 }
124
125 pub fn universes_with_ids(&self) -> impl Iterator<Item = (UniverseId, &Universe)> {
126 self.universes.iter().map(|(id, u)| (*id, u))
127 }
128
129 pub fn universes_with_ids_mut(&mut self) -> impl Iterator<Item = (UniverseId, &mut Universe)> {
130 self.universes.iter_mut().map(|(id, u)| (*id, u))
131 }
132
133 pub fn insert_pipeline<T>(&mut self, pipeline: T) -> PipelineId
134 where
135 T: PipelineEngine + 'static + Send + Sync,
136 {
137 let id = PipelineId::new();
138 self.pipelines.insert(id, Box::new(pipeline));
139 id
140 }
141
142 pub fn remove_pipeline(&mut self, id: PipelineId) {
143 self.bindings.retain(|_, p| p != &id);
144 self.pipelines.remove(&id);
145 }
146
147 pub fn pipeline_ids(&self) -> impl Iterator<Item = PipelineId> + '_ {
148 self.pipelines.keys().cloned()
149 }
150
151 pub fn bind(&mut self, universe: UniverseId, pipeline: PipelineId) {
152 self.bindings.insert(universe, pipeline);
153 }
154
155 pub fn unbind(&mut self, universe: UniverseId) {
156 self.bindings.remove(&universe);
157 }
158
159 pub fn unbind_all(&mut self) {
160 self.bindings.clear();
161 }
162
163 pub fn is_running(&self) -> bool {
164 self.bindings.keys().any(|id| {
165 self.universes
166 .get(id)
167 .map(|u| u.is_running())
168 .unwrap_or_default()
169 })
170 }
171
172 pub fn process(&mut self) {
173 #[cfg(not(feature = "parallel"))]
174 {
175 for (universe, pipeline) in &self.bindings {
176 if let (Some(universe), Some(pipeline)) = (
177 self.universes.get_mut(universe),
178 self.pipelines.get(pipeline),
179 ) {
180 if !universe.paused_systems_execution {
181 pipeline.run(universe);
182 }
183 }
184 }
185 for universe in self.universes.values_mut() {
186 universe.maintain();
187 }
188 }
189 #[cfg(feature = "parallel")]
190 {
191 if self.parallel && self.bindings.len() > 1 {
192 use rayon::prelude::*;
193 let bindings = self
194 .bindings
195 .iter()
196 .map(|(u, p)| (*u, *p))
197 .collect::<Vec<_>>();
198 bindings.into_par_iter().for_each(|(universe, pipeline)| {
199 if let (Some(universe), Some(pipeline)) =
200 (self.universes.get(&universe), self.pipelines.get(&pipeline))
201 {
202 if !universe.paused_systems_execution {
203 #[allow(mutable_transmutes)]
204 #[allow(clippy::transmute_ptr_to_ptr)]
205 pipeline.run(unsafe { std::mem::transmute(universe) });
206 }
207 }
208 });
209 self.universes
210 .par_iter_mut()
211 .for_each(|(_, universe)| universe.maintain());
212 } else {
213 for (universe, pipeline) in &self.bindings {
214 if let (Some(universe), Some(pipeline)) = (
215 self.universes.get_mut(universe),
216 self.pipelines.get(pipeline),
217 ) {
218 if !universe.paused_systems_execution {
219 pipeline.run(universe);
220 }
221 }
222 }
223 for universe in self.universes.values_mut() {
224 universe.maintain();
225 }
226 }
227 }
228 }
229}
230
231pub struct Universe {
232 resources: HashMap<TypeId, Arc<RwLock<Box<Resource>>>>,
233 states: Vec<Box<dyn State>>,
234 startup: bool,
235 pub paused_systems_execution: bool,
236 world: Arc<RwLock<World>>,
237}
238
239impl Default for Universe {
240 fn default() -> Self {
241 Self {
242 resources: Default::default(),
243 states: vec![],
244 startup: true,
245 paused_systems_execution: false,
246 world: Default::default(),
247 }
248 }
249}
250
251impl Universe {
252 pub fn new<S>(state: S) -> Self
253 where
254 S: State + 'static,
255 {
256 Self {
257 resources: Default::default(),
258 states: vec![Box::new(state)],
259 startup: true,
260 paused_systems_execution: false,
261 world: Default::default(),
262 }
263 }
264
265 pub fn world(&self) -> RwLockReadGuard<World> {
266 self.world
267 .try_read()
268 .unwrap_or_else(|error| panic!("{}: {}", std::any::type_name::<World>(), error))
269 }
270
271 pub fn world_mut(&self) -> RwLockWriteGuard<World> {
272 self.world
273 .try_write()
274 .unwrap_or_else(|error| panic!("{}: {}", std::any::type_name::<World>(), error))
275 }
276
277 pub fn try_world(&self) -> Option<RwLockReadGuard<World>> {
278 self.world.try_read().ok()
279 }
280
281 pub fn try_world_mut(&self) -> Option<RwLockWriteGuard<World>> {
282 self.world.try_write().ok()
283 }
284
285 pub fn insert_resource<T>(&mut self, resource: T)
286 where
287 T: 'static + Send + Sync,
288 {
289 self.resources
290 .insert(TypeId::of::<T>(), Arc::new(RwLock::new(Box::new(resource))));
291 }
292
293 pub unsafe fn insert_resource_raw(&mut self, as_type: TypeId, resource: Box<Resource>) {
298 self.resources
299 .insert(as_type, Arc::new(RwLock::new(resource)));
300 }
301
302 pub fn remove_resource<T>(&mut self)
303 where
304 T: 'static,
305 {
306 self.resources.remove(&TypeId::of::<T>());
307 }
308
309 pub fn has_resource<T>(&self) -> bool
310 where
311 T: 'static,
312 {
313 self.resources.contains_key(&TypeId::of::<T>())
314 }
315
316 pub fn resource<T>(&self) -> Option<ResRead<T>>
317 where
318 T: 'static,
319 {
320 if let Some(res) = self.resources.get(&TypeId::of::<T>()) {
321 return Some(ResRead {
322 inner: unsafe {
323 std::mem::transmute(res.try_read().unwrap_or_else(|error| {
324 panic!("{}: {}", std::any::type_name::<T>(), error)
325 }))
326 },
327 _phantom: PhantomData,
328 });
329 }
330 None
331 }
332
333 pub fn resource_mut<T>(&self) -> Option<ResWrite<T>>
334 where
335 T: 'static,
336 {
337 if let Some(res) = self.resources.get(&TypeId::of::<T>()) {
338 return Some(ResWrite {
339 inner: unsafe {
340 std::mem::transmute(res.try_write().unwrap_or_else(|error| {
341 panic!("{}: {}", std::any::type_name::<T>(), error)
342 }))
343 },
344 _phantom: PhantomData,
345 });
346 }
347 None
348 }
349
350 pub fn expect_resource<T>(&self) -> ResRead<T>
351 where
352 T: 'static,
353 {
354 self.resource::<T>()
355 .unwrap_or_else(|| panic!("Resource not found: {}", type_name::<T>()))
356 }
357
358 pub fn expect_resource_mut<T>(&self) -> ResWrite<T>
359 where
360 T: 'static,
361 {
362 self.resource_mut::<T>()
363 .unwrap_or_else(|| panic!("Resource not found: {}", type_name::<T>()))
364 }
365
366 pub fn query_resources<T>(&self) -> T::Fetch
367 where
368 T: ResQuery,
369 {
370 T::fetch(self)
371 }
372
373 pub fn is_running(&self) -> bool {
374 !self.states.is_empty() && self.expect_resource::<AppLifeCycle>().running
375 }
376
377 pub fn maintain(&mut self) {
378 if self.states.is_empty() {
379 return;
380 }
381 self.expect_resource_mut::<EntityChanges>().clear();
382 let mut commands = self.expect_resource_mut::<UniverseCommands>();
383 let executor = commands.execute();
384 drop(commands);
385 executor.execute(self);
386 self.expect_resource_mut::<EntityChanges>()
387 .entities
388 .extend(self.world().iter().map(|entity_ref| entity_ref.entity()));
389 let mut states = std::mem::take(&mut self.states);
390 if self.startup {
391 states.last_mut().unwrap().on_enter(self);
392 self.startup = false;
393 }
394 let count = states.len() - 1;
395 for state in states.iter_mut().take(count) {
396 state.on_process_background(self);
397 }
398 let change = states.last_mut().unwrap().on_process(self);
399 match &change {
400 StateChange::Pop | StateChange::Swap(_) => {
401 let token = self.expect_resource::<AppLifeCycle>().current_state_token();
402 let to_delete = self
403 .world()
404 .query::<&NonPersistent>()
405 .iter()
406 .filter_map(|(entity, pers)| if pers.0 == token { Some(entity) } else { None })
407 .collect::<Vec<_>>();
408 for entity in to_delete {
409 let _ = self.world_mut().despawn(entity);
410 }
411 }
412 StateChange::Quit => {
413 let to_delete = self
414 .world()
415 .query::<&NonPersistent>()
416 .iter()
417 .map(|(entity, _)| entity)
418 .collect::<Vec<_>>();
419 for entity in to_delete {
420 let _ = self.world_mut().despawn(entity);
421 }
422 }
423 _ => {}
424 }
425 match change {
426 StateChange::Push(mut state) => {
427 states.last_mut().unwrap().on_pause(self);
428 self.expect_resource_mut::<AppLifeCycle>()
429 .states_tokens
430 .push(StateToken::new());
431 state.on_enter(self);
432 states.push(state);
433 }
434 StateChange::Pop => {
435 states.pop().unwrap().on_exit(self);
436 self.expect_resource_mut::<AppLifeCycle>()
437 .states_tokens
438 .pop();
439 if let Some(state) = states.last_mut() {
440 state.on_resume(self);
441 }
442 }
443 StateChange::Swap(mut state) => {
444 states.pop().unwrap().on_exit(self);
445 let mut lifecycle = self.expect_resource_mut::<AppLifeCycle>();
446 lifecycle.states_tokens.pop();
447 lifecycle.states_tokens.push(StateToken::new());
448 drop(lifecycle);
449 state.on_enter(self);
450 states.push(state);
451 }
452 StateChange::Quit => {
453 while let Some(mut state) = states.pop() {
454 state.on_exit(self);
455 self.expect_resource_mut::<AppLifeCycle>()
456 .states_tokens
457 .pop();
458 }
459 }
460 _ => {}
461 }
462 self.expect_resource_mut::<AppLifeCycle>().timer.tick();
463
464 let _ = std::mem::replace(&mut self.states, states);
465 }
466}
467
468pub struct UnsafeScope;
469
470impl UnsafeScope {
471 pub unsafe fn lifetime_ref<'a>(&self) -> &'a Self {
475 std::mem::transmute(self)
476 }
477
478 pub unsafe fn lifetime_mut<'a>(&mut self) -> &'a mut Self {
482 std::mem::transmute(self)
483 }
484}
485
486pub struct UnsafeRef<'a, T>(&'a UnsafeScope, &'a T);
487
488impl<'a, T> UnsafeRef<'a, T> {
489 pub unsafe fn upgrade(scope: &'a UnsafeScope, v: &T) -> Self {
493 Self(scope, std::mem::transmute(v))
494 }
495
496 pub unsafe fn read(&self) -> &T {
500 self.1
501 }
502}
503
504pub struct UnsafeMut<'a, T>(&'a UnsafeScope, &'a mut T);
505
506impl<'a, T> UnsafeMut<'a, T> {
507 pub unsafe fn upgrade(scope: &'a UnsafeScope, v: &mut T) -> Self {
511 Self(scope, std::mem::transmute(v))
512 }
513
514 pub unsafe fn read(&self) -> &T {
518 self.1
519 }
520
521 pub unsafe fn write(&mut self) -> &mut T {
525 self.1
526 }
527}
528
529pub trait ResAccess {}
530
531impl ResAccess for () {}
532
533pub type ResQueryItem<Q> = <Q as ResQuery>::Fetch;
534
535pub trait ResQuery {
536 type Fetch: ResAccess;
537
538 fn fetch(universe: &Universe) -> Self::Fetch;
539}
540
541pub struct ResRead<T> {
542 inner: RwLockReadGuard<'static, Box<Resource>>,
543 _phantom: PhantomData<fn() -> T>,
544}
545
546impl<T> ResAccess for ResRead<T> {}
547
548impl<T> Deref for ResRead<T>
549where
550 T: 'static,
551{
552 type Target = T;
553
554 fn deref(&self) -> &Self::Target {
555 self.inner.downcast_ref::<Self::Target>().unwrap()
556 }
557}
558
559pub struct RefRead<T>(RwLockReadGuard<'static, T>)
560where
561 T: 'static;
562
563impl<T> ResAccess for RefRead<T> {}
564
565impl<T> Deref for RefRead<T> {
566 type Target = T;
567
568 fn deref(&self) -> &Self::Target {
569 &self.0
570 }
571}
572
573pub struct ResWrite<T> {
574 inner: RwLockWriteGuard<'static, Box<Resource>>,
575 _phantom: PhantomData<fn() -> T>,
576}
577
578impl<T> ResAccess for ResWrite<T> {}
579
580impl<T> Deref for ResWrite<T>
581where
582 T: 'static,
583{
584 type Target = T;
585
586 fn deref(&self) -> &Self::Target {
587 self.inner.downcast_ref::<Self::Target>().unwrap()
588 }
589}
590
591impl<T> DerefMut for ResWrite<T>
592where
593 T: 'static,
594{
595 fn deref_mut(&mut self) -> &mut Self::Target {
596 self.inner.downcast_mut::<Self::Target>().unwrap()
597 }
598}
599
600pub struct RefWrite<T>(RwLockWriteGuard<'static, T>)
601where
602 T: 'static;
603
604impl<T> ResAccess for RefWrite<T> {}
605
606impl<T> Deref for RefWrite<T> {
607 type Target = T;
608
609 fn deref(&self) -> &Self::Target {
610 &self.0
611 }
612}
613
614impl<T> DerefMut for RefWrite<T> {
615 fn deref_mut(&mut self) -> &mut Self::Target {
616 &mut self.0
617 }
618}
619
620impl<T> ResAccess for Option<T> where T: ResAccess {}
621
622impl ResQuery for WorldRef {
623 type Fetch = RefRead<World>;
624
625 fn fetch(universe: &Universe) -> Self::Fetch {
626 RefRead(unsafe { std::mem::transmute(universe.world()) })
627 }
628}
629
630impl ResQuery for () {
631 type Fetch = ();
632
633 fn fetch(_: &Universe) -> Self::Fetch {}
634}
635
636impl<T> ResQuery for Comp<T> {
637 type Fetch = ();
638
639 fn fetch(_: &Universe) -> Self::Fetch {}
640}
641
642impl<T> ResQuery for &T
643where
644 T: 'static,
645{
646 type Fetch = ResRead<T>;
647
648 fn fetch(universe: &Universe) -> Self::Fetch {
649 universe.expect_resource::<T>()
650 }
651}
652
653impl<T> ResQuery for &mut T
654where
655 T: 'static,
656{
657 type Fetch = ResWrite<T>;
658
659 fn fetch(universe: &Universe) -> Self::Fetch {
660 universe.expect_resource_mut::<T>()
661 }
662}
663
664impl<T> ResQuery for Option<&T>
665where
666 T: 'static,
667{
668 type Fetch = Option<ResRead<T>>;
669
670 fn fetch(universe: &Universe) -> Self::Fetch {
671 universe.resource::<T>()
672 }
673}
674
675impl<T> ResQuery for Option<&mut T>
676where
677 T: 'static,
678{
679 type Fetch = Option<ResWrite<T>>;
680
681 fn fetch(universe: &Universe) -> Self::Fetch {
682 universe.resource_mut::<T>()
683 }
684}
685
686macro_rules! impl_res_query {
687 ( $( $ty:ident ),+ ) => {
688 impl<$( $ty ),+> ResAccess for ( $( $ty, )+ ) where $( $ty: ResAccess ),+ {}
689
690 impl<$( $ty ),+> ResQuery for ( $( $ty, )+ ) where $( $ty: ResQuery ),+ {
691 type Fetch = ( $( $ty::Fetch, )+ );
692
693 fn fetch(universe: &Universe) -> Self::Fetch {
694 ( $( $ty::fetch(universe), )+ )
695 }
696 }
697 }
698}
699
700impl_res_query!(A);
701impl_res_query!(A, B);
702impl_res_query!(A, B, C);
703impl_res_query!(A, B, C, D);
704impl_res_query!(A, B, C, D, E);
705impl_res_query!(A, B, C, D, E, F);
706impl_res_query!(A, B, C, D, E, F, G);
707impl_res_query!(A, B, C, D, E, F, G, H);
708impl_res_query!(A, B, C, D, E, F, G, H, I);
709impl_res_query!(A, B, C, D, E, F, G, H, I, J);
710impl_res_query!(A, B, C, D, E, F, G, H, I, J, K);
711impl_res_query!(A, B, C, D, E, F, G, H, I, J, K, L);
712impl_res_query!(A, B, C, D, E, F, G, H, I, J, K, L, M);
713impl_res_query!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
714impl_res_query!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
715
716pub trait AccessType {
717 fn feed_types(_reads: &mut HashSet<TypeId>, _writes: &mut HashSet<TypeId>) {}
718
719 fn get_types() -> (HashSet<TypeId>, HashSet<TypeId>) {
721 let mut reads = HashSet::new();
722 let mut writes = HashSet::new();
723 Self::feed_types(&mut reads, &mut writes);
724 (reads, writes)
725 }
726}
727
728impl AccessType for () {}
729
730impl AccessType for WorldRef {
731 fn feed_types(reads: &mut HashSet<TypeId>, _: &mut HashSet<TypeId>) {
732 reads.insert(TypeId::of::<World>());
733 }
734}
735
736impl<T> AccessType for Comp<T>
737where
738 T: AccessType,
739{
740 fn feed_types(reads: &mut HashSet<TypeId>, writes: &mut HashSet<TypeId>) {
741 T::feed_types(reads, writes);
742 }
743}
744
745impl<T> AccessType for &T
746where
747 T: 'static,
748{
749 fn feed_types(reads: &mut HashSet<TypeId>, _: &mut HashSet<TypeId>) {
750 reads.insert(TypeId::of::<T>());
751 }
752}
753
754impl<T> AccessType for &mut T
755where
756 T: 'static,
757{
758 fn feed_types(_: &mut HashSet<TypeId>, writes: &mut HashSet<TypeId>) {
759 writes.insert(TypeId::of::<T>());
760 }
761}
762
763macro_rules! impl_access_type {
764 ( $( $ty:ident ),+ ) => {
765 impl<$( $ty ),+> AccessType for ( $( $ty, )+ ) where $( $ty: AccessType ),+ {
766 fn feed_types(reads: &mut HashSet<TypeId>,writes: &mut HashSet<TypeId>) {
767 $( $ty::feed_types(reads, writes); )+
768 }
769 }
770 }
771}
772
773impl_access_type!(A);
774impl_access_type!(A, B);
775impl_access_type!(A, B, C);
776impl_access_type!(A, B, C, D);
777impl_access_type!(A, B, C, D, E);
778impl_access_type!(A, B, C, D, E, F);
779impl_access_type!(A, B, C, D, E, F, G);
780impl_access_type!(A, B, C, D, E, F, G, H);
781impl_access_type!(A, B, C, D, E, F, G, H, I);
782impl_access_type!(A, B, C, D, E, F, G, H, I, J);
783impl_access_type!(A, B, C, D, E, F, G, H, I, J, K);
784impl_access_type!(A, B, C, D, E, F, G, H, I, J, K, L);
785impl_access_type!(A, B, C, D, E, F, G, H, I, J, K, L, M);
786impl_access_type!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
787impl_access_type!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
788
789#[cfg(test)]
790mod tests {
791 use super::*;
792
793 #[test]
794 fn test_send_sync() {
795 fn foo<T: Send + Sync>() {
796 println!("{} is Send + Sync", std::any::type_name::<T>());
797 }
798
799 foo::<Universe>();
800 foo::<Multiverse>();
801 }
802}