oxygengine_core/ecs/
life_cycle.rs

1use crate::{
2    app::AppBuilder,
3    ecs::{
4        components::{Events, EventsPrefabProxy},
5        pipeline::{PipelineBuilder, PipelineBuilderError, PipelineLayer},
6        Comp, Entity, Universe, WorldRef,
7    },
8    prefab::PrefabManager,
9};
10use std::{
11    any::TypeId,
12    collections::{HashMap, HashSet},
13};
14
15#[derive(Debug, Default)]
16pub struct EntityChanges {
17    pub skip_clearing: bool,
18    pub(crate) entities: HashSet<Entity>,
19    pub(crate) spawned: HashSet<Entity>,
20    pub(crate) despawned: HashSet<Entity>,
21    pub(crate) added_components: HashMap<Entity, HashSet<TypeId>>,
22    pub(crate) removed_components: HashMap<Entity, HashSet<TypeId>>,
23}
24
25impl EntityChanges {
26    pub fn has_changed(&self) -> bool {
27        !self.spawned.is_empty() || !self.despawned.is_empty()
28    }
29
30    pub fn entities(&self) -> impl Iterator<Item = Entity> + '_ {
31        self.entities.iter().copied()
32    }
33
34    pub fn spawned(&self) -> impl Iterator<Item = Entity> + '_ {
35        self.spawned.iter().copied()
36    }
37
38    pub fn has_spawned(&self, entity: Entity) -> bool {
39        self.spawned.contains(&entity)
40    }
41
42    pub fn despawned(&self) -> impl Iterator<Item = Entity> + '_ {
43        self.despawned.iter().copied()
44    }
45
46    pub fn has_despawned(&self, entity: Entity) -> bool {
47        self.despawned.contains(&entity)
48    }
49
50    pub fn added_component_iter<T: 'static>(&self) -> impl Iterator<Item = Entity> + '_ {
51        let type_id = TypeId::of::<T>();
52        self.added_components
53            .iter()
54            .filter_map(move |(entity, types)| {
55                if types.contains(&type_id) {
56                    Some(*entity)
57                } else {
58                    None
59                }
60            })
61    }
62
63    pub fn added_components(&self, entity: Entity) -> Option<impl Iterator<Item = TypeId> + '_> {
64        self.added_components
65            .get(&entity)
66            .map(|types| types.iter().copied())
67    }
68
69    pub fn has_added_component<T: 'static>(&self, entity: Entity) -> bool {
70        let type_id = TypeId::of::<T>();
71        self.added_components
72            .get(&entity)
73            .map(|types| types.contains(&type_id))
74            .unwrap_or_default()
75    }
76
77    pub fn removed_component_iter<T: 'static>(&self) -> impl Iterator<Item = Entity> + '_ {
78        let type_id = TypeId::of::<T>();
79        self.removed_components
80            .iter()
81            .filter_map(move |(entity, types)| {
82                if types.contains(&type_id) {
83                    Some(*entity)
84                } else {
85                    None
86                }
87            })
88    }
89
90    pub fn removed_components(&self, entity: Entity) -> Option<impl Iterator<Item = TypeId> + '_> {
91        self.removed_components
92            .get(&entity)
93            .map(|types| types.iter().copied())
94    }
95
96    pub fn has_removed_component<T: 'static>(&self, entity: Entity) -> bool {
97        let type_id = TypeId::of::<T>();
98        self.removed_components
99            .get(&entity)
100            .map(|types| types.contains(&type_id))
101            .unwrap_or_default()
102    }
103
104    pub(crate) fn clear(&mut self) {
105        if self.skip_clearing {
106            self.skip_clearing = false;
107            return;
108        }
109        self.entities.clear();
110        self.spawned.clear();
111        self.despawned.clear();
112        self.added_components.clear();
113        self.removed_components.clear();
114    }
115}
116
117pub type EventsSystemResources<'a, T> = (WorldRef, Comp<&'a mut Events<T>>);
118
119pub fn events_system<T>(universe: &mut Universe)
120where
121    T: Send + Sync + 'static,
122{
123    let (world, ..) = universe.query_resources::<EventsSystemResources<T>>();
124
125    for (_, events) in world.query::<&mut Events<T>>().iter() {
126        if events.auto_clear {
127            events.clear();
128        }
129    }
130}
131
132pub fn events_system_installer<PB, T>(
133    builder: &mut AppBuilder<PB>,
134    postfix: &str,
135) -> Result<(), PipelineBuilderError>
136where
137    PB: PipelineBuilder,
138    T: Send + Sync + 'static,
139{
140    builder.install_system_on_layer::<EventsSystemResources<T>>(
141        &format!("events-system-{}", postfix),
142        events_system::<T>,
143        &[],
144        PipelineLayer::Post,
145        false,
146    )?;
147    Ok(())
148}
149
150pub fn events_prefab_installer<T>(postfix: &str, prefabs: &mut PrefabManager)
151where
152    T: Send + Sync + 'static,
153{
154    prefabs.register_component_factory_proxy::<Events<T>, EventsPrefabProxy<T>>(&format!(
155        "Events-{}",
156        postfix
157    ));
158}