1#![deprecated(
2 since = "0.2.4",
3 note = "see documentation at https://github.com/Zeenobit/moonshine_spawn for details"
4)]
5#![doc = include_str!("../README.md")]
6
7use std::fmt::{Debug, Formatter, Result as FormatResult};
8use std::hash::{Hash, Hasher};
9use std::sync::Arc;
10
11use bevy_app::prelude::*;
12use bevy_ecs::prelude::*;
13use bevy_ecs::schedule::SystemConfigs;
14use bevy_ecs::system::EntityCommands;
15use bevy_hierarchy::BuildChildren;
16use bevy_reflect::prelude::*;
17use bevy_utils::HashMap;
18
19pub mod prelude {
20 pub use super::{
21 spawn_children, AddSpawnable, Spawn, SpawnChildBuilder, SpawnChildren, SpawnCommands,
22 SpawnKey, SpawnOnce, SpawnPlugin, SpawnWorld, Spawnables, WithChildren,
23 };
24}
25
26pub struct SpawnPlugin;
27
28impl Plugin for SpawnPlugin {
29 fn build(&self, app: &mut App) {
30 app.register_type::<SpawnKey>()
31 .insert_resource(Spawnables::default())
32 .add_systems(First, invoke_spawn_children.run_if(should_spawn_children));
33 }
34}
35
36pub trait SpawnOnce: 'static + Send + Sync {
43 type Output: Bundle;
44
45 fn spawn_once(self, world: &World, entity: Entity) -> Self::Output;
46}
47
48impl<T: Bundle> SpawnOnce for T {
49 type Output = Self;
50
51 fn spawn_once(self, _: &World, _: Entity) -> Self::Output {
52 self
53 }
54}
55
56pub trait Spawn: 'static + Send + Sync {
64 type Output: Bundle;
65
66 fn spawn(&self, world: &World, entity: Entity) -> Self::Output;
67}
68
69impl<T: SpawnOnce + Clone> Spawn for T {
70 type Output = T::Output;
71
72 fn spawn(&self, world: &World, entity: Entity) -> Self::Output {
73 self.clone().spawn_once(world, entity)
74 }
75}
76
77pub trait AddSpawnable {
83 fn add_spawnable(self, key: impl Into<SpawnKey>, _: impl Spawn) -> SpawnKey;
84}
85
86impl AddSpawnable for &mut App {
87 fn add_spawnable(self, key: impl Into<SpawnKey>, spawnable: impl Spawn) -> SpawnKey {
88 self.world_mut()
89 .resource_mut::<Spawnables>()
90 .register(key, spawnable)
91 }
92}
93
94pub trait SpawnCommands {
96 fn spawn_with(&mut self, _: impl Spawn) -> EntityCommands<'_>;
97
98 fn spawn_once_with(&mut self, _: impl SpawnOnce) -> EntityCommands<'_>;
99
100 fn spawn_key(&mut self, key: impl Into<SpawnKey>) -> EntityCommands<'_>;
101
102 fn spawn_key_with(
103 &mut self,
104 key: impl Into<SpawnKey>,
105 bundle: impl Bundle,
106 ) -> EntityCommands<'_>;
107}
108
109impl SpawnCommands for Commands<'_, '_> {
110 fn spawn_with(&mut self, spawnable: impl Spawn) -> EntityCommands<'_> {
111 let entity = self.spawn_empty().id();
112 self.queue(move |world: &mut World| {
113 Spawnable::spawn(&spawnable, world, entity);
114 });
115 self.entity(entity)
116 }
117
118 fn spawn_once_with(&mut self, spawnable: impl SpawnOnce) -> EntityCommands<'_> {
119 let entity = self.spawn_empty().id();
120 self.queue(move |world: &mut World| {
121 SpawnableOnce::spawn_once(spawnable, world, entity);
122 });
123 self.entity(entity)
124 }
125
126 fn spawn_key(&mut self, key: impl Into<SpawnKey>) -> EntityCommands<'_> {
127 let key: SpawnKey = key.into();
128 let entity = self.spawn_empty().id();
129 self.queue(move |world: &mut World| {
130 key.spawn_once(world, entity);
131 });
132 self.entity(entity)
133 }
134
135 fn spawn_key_with(
136 &mut self,
137 key: impl Into<SpawnKey>,
138 bundle: impl Bundle,
139 ) -> EntityCommands<'_> {
140 let key = key.into();
141 let entity = self.spawn_empty().id();
142 self.queue(move |world: &mut World| {
143 SpawnKeyWith(key, bundle).spawn_once(world, entity);
144 });
145 self.entity(entity)
146 }
147}
148
149pub trait SpawnWorld {
151 fn spawn_with(&mut self, _: impl Spawn) -> EntityWorldMut;
152
153 fn spawn_once_with(&mut self, _: impl SpawnOnce) -> EntityWorldMut;
154
155 fn spawn_key(&mut self, key: impl Into<SpawnKey>) -> EntityWorldMut;
156
157 fn spawn_key_with(&mut self, key: impl Into<SpawnKey>, bundle: impl Bundle) -> EntityWorldMut;
158}
159
160impl SpawnWorld for World {
161 fn spawn_with(&mut self, spawnable: impl Spawn) -> EntityWorldMut {
162 let entity = self.spawn_empty().id();
163 Spawnable::spawn(&spawnable, self, entity);
164 invoke_spawn_children(self);
165 self.entity_mut(entity)
166 }
167
168 fn spawn_once_with(&mut self, spawnable: impl SpawnOnce) -> EntityWorldMut {
169 let entity = self.spawn_empty().id();
170 SpawnableOnce::spawn_once(spawnable, self, entity);
171 invoke_spawn_children(self);
172 self.entity_mut(entity)
173 }
174
175 fn spawn_key(&mut self, key: impl Into<SpawnKey>) -> EntityWorldMut {
176 let key: SpawnKey = key.into();
177 let entity = self.spawn_empty().id();
178 key.spawn_once(self, entity);
179 invoke_spawn_children(self);
180 self.entity_mut(entity)
181 }
182
183 fn spawn_key_with(&mut self, key: impl Into<SpawnKey>, bundle: impl Bundle) -> EntityWorldMut {
184 let key = key.into();
185 let entity = self.spawn_empty().id();
186 SpawnKeyWith(key, bundle).spawn_once(self, entity);
187 invoke_spawn_children(self);
188 self.entity_mut(entity)
189 }
190}
191
192#[derive(Resource, Default)]
194pub struct Spawnables(HashMap<SpawnKey, Arc<dyn Spawnable>>);
195
196impl Spawnables {
197 pub fn register<T>(&mut self, key: impl Into<SpawnKey>, spawnable: T) -> SpawnKey
202 where
203 T: 'static + Spawn + Send + Sync,
204 {
205 let key = key.into();
206 let previous = self.0.insert(key.clone(), Arc::new(spawnable));
207 assert!(previous.is_none(), "spawn key must be unique: {key:?}",);
208 key
209 }
210
211 pub fn keys(&self) -> impl Iterator<Item = &SpawnKey> {
213 self.0.keys()
214 }
215
216 fn fetch(&self, key: &SpawnKey) -> Option<Arc<dyn Spawnable>> {
217 self.0.get(key).cloned()
218 }
219}
220
221#[derive(Clone, Reflect)]
223pub struct SpawnKey(String);
224
225impl SpawnKey {
226 pub fn new(name: impl Into<String>) -> Self {
227 Self(name.into())
228 }
229
230 pub fn name(&self) -> &str {
231 &self.0
232 }
233}
234
235impl PartialEq for SpawnKey {
236 fn eq(&self, other: &Self) -> bool {
237 self.name() == other.name()
238 }
239}
240
241impl Eq for SpawnKey {}
242
243impl Hash for SpawnKey {
244 fn hash<H: Hasher>(&self, state: &mut H) {
245 self.name().hash(state)
246 }
247}
248
249impl Debug for SpawnKey {
250 fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
251 f.debug_tuple("SpawnKey").field(&self.name()).finish()
252 }
253}
254
255impl From<String> for SpawnKey {
256 fn from(name: String) -> Self {
257 Self(name)
258 }
259}
260
261impl From<&str> for SpawnKey {
262 fn from(name: &str) -> Self {
263 Self(name.to_owned())
264 }
265}
266
267pub trait WithChildren: Bundle + Sized {
286 fn with_children(self, f: impl FnOnce(&mut SpawnChildBuilder)) -> (Self, SpawnChildren);
287}
288
289impl<T: Bundle> WithChildren for T {
290 fn with_children(self, f: impl FnOnce(&mut SpawnChildBuilder)) -> (Self, SpawnChildren) {
291 let mut children = SpawnChildren::new();
292 let mut builder = SpawnChildBuilder(&mut children);
293 f(&mut builder);
294 (self, children)
295 }
296}
297
298#[derive(Component)]
300#[component(storage = "SparseSet")]
301pub struct SpawnChildren(Vec<Box<dyn SpawnableOnce>>);
302
303impl SpawnChildren {
304 fn new() -> Self {
305 Self(Vec::new())
306 }
307
308 fn add_child(&mut self, spawnable: impl SpawnableOnce) {
309 self.0.push(Box::new(spawnable));
310 }
311
312 fn add_child_with_key(&mut self, key: SpawnKey) {
313 self.0.push(Box::new(key));
314 }
315
316 fn invoke(world: &mut World, entity: Entity, mut child_spawned: impl FnMut(Entity)) {
317 if let Some(children) = world.entity_mut(entity).take::<SpawnChildren>() {
318 for spawnable in children.0 {
319 let child = world.spawn_empty().id();
320 spawnable.spawn_once_dyn(world, child);
321 child_spawned(child);
322 world.entity_mut(entity).add_child(child);
323 }
324 }
325 }
326}
327
328#[must_use]
330pub fn spawn_children(f: impl FnOnce(&mut SpawnChildBuilder)) -> SpawnChildren {
331 let mut children = SpawnChildren::new();
332 f(&mut SpawnChildBuilder(&mut children));
333 children
334}
335
336impl Default for SpawnChildren {
337 fn default() -> Self {
338 Self::new()
339 }
340}
341
342pub struct SpawnChildBuilder<'a>(&'a mut SpawnChildren);
343
344impl SpawnChildBuilder<'_> {
345 pub fn spawn(&mut self, spawnable: impl SpawnOnce) -> &mut Self {
346 self.0.add_child(spawnable);
347 self
348 }
349
350 pub fn spawn_key(&mut self, key: impl Into<SpawnKey>) -> &mut Self {
351 self.0.add_child_with_key(key.into());
352 self
353 }
354
355 pub fn spawn_key_with(&mut self, key: impl Into<SpawnKey>, bundle: impl Bundle) -> &mut Self {
356 self.0.add_child(SpawnKeyWith(key.into(), bundle));
357 self
358 }
359}
360
361trait Spawnable: 'static + Send + Sync {
362 fn spawn(&self, world: &mut World, entity: Entity);
363}
364
365impl<T: Spawn> Spawnable for T {
366 fn spawn(&self, world: &mut World, entity: Entity) {
367 let bundle = self.spawn(world, entity);
368 world.entity_mut(entity).insert(bundle);
369 }
370}
371
372trait SpawnableOnce: 'static + Send + Sync {
373 fn spawn_once(self, world: &mut World, entity: Entity);
374
375 fn spawn_once_dyn(self: Box<Self>, world: &mut World, entity: Entity);
376}
377
378impl<T: SpawnOnce> SpawnableOnce for T {
379 fn spawn_once(self, world: &mut World, entity: Entity) {
380 let bundle = self.spawn_once(world, entity);
381 world.entity_mut(entity).insert(bundle);
382 }
383
384 fn spawn_once_dyn(self: Box<Self>, world: &mut World, entity: Entity) {
385 SpawnableOnce::spawn_once(*self, world, entity);
386 }
387}
388
389impl SpawnableOnce for SpawnKey {
390 fn spawn_once(self, world: &mut World, entity: Entity) {
391 if let Some(spawnable) = world.resource::<Spawnables>().fetch(&self) {
392 spawnable.spawn(world, entity);
393 } else {
394 panic!("invalid spawn key: {self:?}");
395 }
396 }
397
398 fn spawn_once_dyn(self: Box<Self>, world: &mut World, entity: Entity) {
399 SpawnableOnce::spawn_once(*self, world, entity);
400 }
401}
402
403struct SpawnKeyWith<T>(SpawnKey, T);
404
405impl<T: Bundle> SpawnableOnce for SpawnKeyWith<T> {
406 fn spawn_once(self, world: &mut World, entity: Entity) {
407 self.0.spawn_once(world, entity);
408 world.entity_mut(entity).insert(self.1);
409 }
410
411 fn spawn_once_dyn(self: Box<Self>, world: &mut World, entity: Entity) {
412 SpawnableOnce::spawn_once(*self, world, entity);
413 }
414}
415
416fn should_spawn_children(query: Query<(), With<SpawnChildren>>) -> bool {
417 !query.is_empty()
418}
419
420fn invoke_spawn_children(world: &mut World) {
421 let mut entities = Vec::new();
422
423 for entity in world.iter_entities() {
424 if entity.contains::<SpawnChildren>() {
425 entities.push(entity.id());
426 }
427 }
428
429 while !entities.is_empty() {
430 let batch = std::mem::take(&mut entities);
431 for entity in batch {
432 SpawnChildren::invoke(world, entity, |child| entities.push(child));
433 }
434 }
435}
436
437pub fn force_spawn_children() -> SystemConfigs {
482 invoke_spawn_children.run_if(should_spawn_children)
483}
484
485#[cfg(test)]
486mod tests {
487 use bevy::{ecs::system::RunSystemOnce, prelude::*};
488
489 use super::*;
490
491 fn app() -> App {
492 let mut app = App::new();
493 app.add_plugins((MinimalPlugins, SpawnPlugin));
494 app
495 }
496
497 #[derive(Component, Clone)]
498 struct Foo;
499
500 #[derive(Component, Clone)]
501 struct Bar;
502
503 #[test]
504 fn spawn_bundle() {
505 let mut app = app();
506 let world = app.world_mut();
507 let entity = world.spawn_once_with(Foo).id();
508 assert!(world.entity(entity).contains::<Foo>());
509 }
510
511 #[test]
512 fn spawn_bundle_deferred() {
513 let mut app = app();
514 let entity = {
515 let world = app.world_mut();
516 world
517 .run_system_once(|mut commands: Commands| commands.spawn_once_with(Foo).id())
518 .unwrap()
519 };
520 app.update();
521 let world = app.world();
522 assert!(world.entity(entity).contains::<Foo>());
523 }
524
525 #[test]
526 fn spawn_with_key() {
527 let mut app = app();
528 app.add_spawnable("FOO", Foo);
529 let world = app.world_mut();
530 let entity = world.spawn_key("FOO").id();
531 assert!(world.entity(entity).contains::<Foo>());
532 }
533
534 #[test]
535 fn spawn_with_key_deferred() {
536 let mut app = app();
537 app.add_spawnable("FOO", Foo);
538 let entity = {
539 let world = app.world_mut();
540 world
541 .run_system_once(|mut commands: Commands| commands.spawn_key("FOO").id())
542 .unwrap()
543 };
544 app.update();
545 let world = app.world();
546 assert!(world.entity(entity).contains::<Foo>());
547 }
548
549 #[test]
550 fn spawn_bundle_with_children() {
551 let mut app = app();
552 let world = app.world_mut();
553 let entity = world
554 .spawn_once_with(Foo.with_children(|foo| {
555 foo.spawn(Bar);
556 }))
557 .id();
558 let children = world.entity(entity).get::<Children>().unwrap();
559 let child = children.iter().copied().next().unwrap();
560 assert!(world.entity(child).contains::<Bar>());
561 }
562
563 #[test]
564 fn spawn_bundle_with_children_deferred() {
565 let mut app = app();
566 let entity = {
567 let world = app.world_mut();
568 world
569 .run_system_once(|mut commands: Commands| {
570 commands
571 .spawn_once_with(Foo.with_children(|foo| {
572 foo.spawn(Bar);
573 }))
574 .id()
575 })
576 .unwrap()
577 };
578 app.update();
579 let world = app.world();
580 let children = world.entity(entity).get::<Children>().unwrap();
581 let child = children.iter().copied().next().unwrap();
582 assert!(world.entity(child).contains::<Bar>());
583 }
584
585 #[test]
586 fn spawn_bundle_with_children_with_key() {
587 let mut app = app();
588 app.add_spawnable("BAR", Bar);
589 let world = app.world_mut();
590 let entity = world
591 .spawn_once_with(Foo.with_children(|foo| {
592 foo.spawn_key("BAR");
593 }))
594 .id();
595 let children = world.entity(entity).get::<Children>().unwrap();
596 let child = children.iter().copied().next().unwrap();
597 assert!(world.entity(child).contains::<Bar>());
598 }
599
600 #[test]
601 fn spawn_bundle_with_children_with_key_deferred() {
602 let mut app = app();
603 app.add_spawnable("BAR", Bar);
604 let entity = {
605 let world = app.world_mut();
606 world
607 .run_system_once(|mut commands: Commands| {
608 commands
609 .spawn_once_with(Foo.with_children(|foo| {
610 foo.spawn_key("BAR");
611 }))
612 .id()
613 })
614 .unwrap()
615 };
616 app.update();
617 let world = app.world();
618 let children = world.entity(entity).get::<Children>().unwrap();
619 let child = children.iter().copied().next().unwrap();
620 assert!(world.entity(child).contains::<Bar>());
621 }
622}