oxygengine_core/ecs/
life_cycle.rs1use 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}