1use crate::{
2 ChildIndex, ChildOrder, Compose, Root, Scope, SetState,
3 modify::{Modifier, Modify},
4 scope::ScopeId,
5};
6use bevy_ecs::{
7 bundle::Bundle,
8 component::Component,
9 entity::Entity,
10 system::{Commands, Query},
11};
12use bevy_hierarchy::{BuildChildren, DespawnRecursiveExt};
13use std::{collections::BTreeMap, sync::Arc};
14
15#[derive(Clone)]
19pub struct Spawn<B: Bundle + Clone> {
20 pub(crate) bundle_generator: Arc<dyn (Fn() -> B) + Send + Sync>,
21 pub(crate) modifier: Modifier,
22}
23
24impl<B: Bundle + Clone> Spawn<B> {
25 pub fn new(bundle: B) -> Self {
27 Self {
28 bundle_generator: Arc::new(move || bundle.clone()),
29 modifier: Modifier::default(),
30 }
31 }
32}
33
34impl<B: Bundle + Clone> Modify for Spawn<B> {
35 fn modifier(&mut self) -> &mut Modifier {
36 &mut self.modifier
37 }
38}
39
40impl<B: Bundle + Clone> Compose for Spawn<B> {
41 fn compose<'a>(&self, cx: &mut Scope) -> impl Compose + 'a {
42 let entity = cx.use_state(None);
43 let should_update = cx.use_state(true);
44 let bundle_updater = cx.use_state::<Box<
45 dyn Fn(Entity, ChildIndex, &mut Commands, &mut SetState) + Send + Sync,
46 >>(Box::new(
47 |_: Entity, _: ChildIndex, _: &mut Commands, _: &mut SetState| {},
48 ));
49 let temporary_observers = cx.use_state(Vec::new());
50
51 if let Some(entity) = *entity {
52 cx.set_entity(entity);
53 };
54
55 let retained_observer_generators = self.modifier.retained_observers.clone();
56 let scope_id = cx.id;
57
58 cx.use_system_once(move |mut state: SetState, mut commands: Commands| {
59 let mut ec = commands.spawn(SpawnComposable(scope_id));
60
61 retained_observer_generators.iter().for_each(|generator| {
62 generator.generate(&mut ec);
63 });
64
65 state.set(&entity, Some(ec.id()));
66 });
67
68 let generator = self.bundle_generator.clone();
69 let temporary_observer_generators = self.modifier.temporary_observers.clone();
70 let temporary_observer_entities = temporary_observers.clone();
71 let conditional_bundles = self.modifier.bundle_modifiers.clone();
72 let parent_entity = cx.parent_entity;
73 cx.set_state_unchanged(&should_update, true);
81 cx.set_state_unchanged(
82 &bundle_updater,
83 Box::new(
84 move |entity: Entity,
85 child_index: ChildIndex,
86 commands: &mut Commands,
87 state: &mut SetState| {
88 for observer_entity in temporary_observer_entities.iter() {
89 let Some(observer_ec) = commands.get_entity(*observer_entity) else {
90 continue;
91 };
92
93 observer_ec.try_despawn_recursive();
94 }
95
96 let bundle = generator();
97 let mut ec = commands.entity(entity);
98
99 for conditional_bundle in conditional_bundles.iter() {
100 conditional_bundle(&mut ec);
101 }
102
103 ec.try_insert((bundle, ChildOrder(child_index)))
104 .set_parent(parent_entity);
105
106 let observer_entities = temporary_observer_generators
107 .iter()
108 .map(|generator| generator.generate(&mut ec))
109 .collect::<Vec<_>>();
110
111 state.set_unchanged(&temporary_observers, observer_entities);
112 },
113 ),
114 );
115
116 self.modifier.children.clone()
117 }
118
119 fn decompose(&self, cx: &mut Scope) {
120 let entity = cx.get_state_by_index::<Option<Entity>>(0);
121
122 if let Some(entity) = *entity {
123 cx.use_system_once(move |mut commands: Commands| {
124 let Some(ec) = commands.get_entity(entity) else {
125 return;
126 };
127 ec.try_despawn_recursive();
128 });
129 }
130 }
131
132 fn name(&self) -> String {
133 String::from("Spawn")
134 }
135}
136
137#[derive(Component, Debug)]
138pub struct SpawnComposable(ScopeId);
139
140pub fn update_spawn_composables(
141 mut commands: Commands,
142 mut state: SetState,
143 mut roots: Query<&mut Root>,
144 spawn_composables: Query<(Entity, &SpawnComposable)>,
145) {
146 let spawn_composable_lookup = spawn_composables
147 .iter()
148 .map(|sc| (sc.1.0, sc.0))
149 .collect::<BTreeMap<_, _>>();
150
151 for mut root in roots.iter_mut() {
154 let Some(scope) = &mut root.scope else {
155 continue;
156 };
157
158 let mut scopes = Vec::from([scope]);
159
160 while let Some(scope) = scopes.pop() {
161 let spawn_composable = spawn_composable_lookup.get(&scope.id);
162
163 if let Some(entity) = spawn_composable {
164 let should_update = scope.get_state_by_index::<bool>(1);
165
166 if *should_update {
167 let bundle_updater = scope.get_state_by_index::<Box<
168 dyn Fn(Entity, ChildIndex, &mut Commands, &mut SetState) + Send + Sync,
169 >>(2);
170
171 bundle_updater(
172 *entity,
173 scope.child_index.clone(),
176 &mut commands,
177 &mut state,
178 );
179
180 scope.set_state_unchanged(&should_update, false);
181 }
182 }
183
184 scopes.extend(scope.children.iter_mut());
185 }
186 }
187}