spew/plugin.rs
1use crate::events::{delay_spawn_events, ReadySpawnEvent, SpawnEvent};
2use crate::spawner::{Spawner, Spawners};
3use bevy::prelude::*;
4
5#[allow(clippy::needless_doctest_main)]
6/// A plugin that enables spawning objects of type `T` while providing data of type `D`.
7/// Using multiple combinations of `T` and `D` requires adding multiple instances of this plugin to an [`App`].
8/// If your spawn systems don't require any data, simply pass `()` as the `D` type.
9///
10/// # Example
11/// ```rust,ignore
12/// use spew::prelude::*;
13/// use bevy::prelude::*;
14///
15/// #[derive(Debug, Eq, PartialEq)]
16/// enum Object {
17/// Cube
18/// }
19///
20/// fn main() {
21/// App::new()
22/// .add_plugins(DefaultPlugins)
23/// .add_plugins(SpewPlugin::<Object, Transform>::default())
24/// .run();
25/// }
26/// ```
27pub struct SpewPlugin<T, D = ()>
28where
29 T: Eq + Send + Sync + 'static,
30 D: Send + Sync + 'static,
31{
32 _spawner_enum_type: std::marker::PhantomData<T>,
33 _data_type: std::marker::PhantomData<D>,
34}
35
36impl<T, D> Default for SpewPlugin<T, D>
37where
38 T: Eq + Send + Sync + 'static,
39 D: Send + Sync + 'static,
40{
41 fn default() -> Self {
42 Self {
43 _spawner_enum_type: std::marker::PhantomData,
44 _data_type: std::marker::PhantomData,
45 }
46 }
47}
48
49impl<T, D> Plugin for SpewPlugin<T, D>
50where
51 T: Eq + Send + Sync + 'static,
52 D: Send + Sync + 'static,
53{
54 fn build(&self, app: &mut App) {
55 app.add_event::<SpawnEvent<T, D>>()
56 .add_event::<ReadySpawnEvent<T, D>>()
57 .add_systems(Update, delay_spawn_events::<T, D>.in_set(SpewSystemSet));
58 }
59
60 fn is_unique(&self) -> bool {
61 false
62 }
63}
64
65/// The SystemSet that contains all spew systems.
66#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
67pub struct SpewSystemSet;
68
69/// A trait that allows adding spawners to an [`App`].
70/// Spawners are tuples of an object and a spawning function, e.g. `(Object::Cube, spawn_cube)`.
71/// A spawning function has the same signature as a bevy system function, where user provided data is passed as an `In<D>` parameter in the first position.
72///
73/// The spawner's combination of object enum and user data must have been registered with an own [`SpewPlugin`] beforehand.
74pub trait SpewApp {
75 /// Add a single spawner to the app.
76 ///
77 /// # Example
78 /// ```rust,ignore
79 /// use spew::prelude::*;
80 /// use bevy::prelude::*;
81 ///
82 /// #[derive(Debug, Eq, PartialEq)]
83 /// enum Object {
84 /// Cube
85 /// }
86 ///
87 /// fn main() {
88 /// App::new()
89 /// .add_plugins(DefaultPlugins)
90 /// .add_plugins(SpewPlugin::<Object, Transform>::default())
91 /// .add_spawner((Object::Cube, spawn_cube))
92 /// .run();
93 /// }
94 ///
95 /// fn spawn_cube(In(transform): In<Transform>, mut commands: Commands) {
96 /// info!("Spawning cube at {}", transform.translation);
97 /// commands.spawn((Name::new("Cube"), transform));
98 /// }
99 /// ```
100 fn add_spawner<T, D>(&mut self, spawner: T) -> &mut App
101 where
102 T: Spawner<D>;
103
104 /// Add multiple spawners to the app by providing them in a tuple.
105 ///
106 /// # Example
107 /// ```rust,ignore
108 /// use spew::prelude::*;
109 /// use bevy::prelude::*;
110 ///
111 /// #[derive(Debug, Eq, PartialEq)]
112 /// enum Object {
113 /// Cube,
114 /// Triangle,
115 /// Sphere,
116 /// }
117 ///
118 /// fn main() {
119 /// App::new()
120 /// .add_plugins(DefaultPlugins)
121 /// .add_plugins(SpewPlugin::<Object, Transform>::default())
122 /// .add_spawners((
123 /// (Object::Cube, spawn_cube),
124 /// (Object::Triangle, spawn_triangle),
125 /// (Object::Sphere, spawn_sphere),
126 /// ))
127 /// .run();
128 /// }
129 ///
130 /// fn spawn_cube(In(transform): In<Transform>, mut commands: Commands) {
131 /// info!("Spawning cube at {}", transform.translation);
132 /// commands.spawn((Name::new("Cube"), transform));
133 /// }
134 ///
135 /// fn spawn_triangle(In(transform): In<Transform>, mut commands: Commands) {
136 /// info!("Spawning triangle at {}", transform.translation);
137 /// commands.spawn((Name::new("Triangle"), transform));
138 /// }
139 ///
140 /// fn spawn_sphere(In(transform): In<Transform>, mut commands: Commands) {
141 /// info!("Spawning sphere at {}", transform.translation);
142 /// commands.spawn((Name::new("Sphere"), transform));
143 /// }
144 /// ```
145 fn add_spawners<T, D>(&mut self, spawners: T) -> &mut App
146 where
147 T: Spawners<D>;
148}
149
150impl SpewApp for App {
151 fn add_spawner<T, D>(&mut self, spawner: T) -> &mut App
152 where
153 T: Spawner<D>,
154 {
155 spawner.add_to_app(self);
156 self
157 }
158 fn add_spawners<T, D>(&mut self, spawners: T) -> &mut App
159 where
160 T: Spawners<D>,
161 {
162 spawners.add_to_app(self);
163 self
164 }
165}