bevy_async_ecs/
entity.rs

1use crate::command::CommandQueueSender;
2use crate::die;
3use crate::recv;
4use crate::util::despawn;
5use crate::util::insert;
6use crate::util::remove;
7use crate::wait_for::StartWaitingFor;
8use crate::world::AsyncWorld;
9use async_channel::Receiver;
10use async_channel::Sender;
11use async_channel::TrySendError;
12use bevy_ecs::prelude::*;
13use std::fmt;
14
15/// Represents an `Entity` that can be manipulated asynchronously.
16///
17/// The easiest way to get an `AsyncEntity` is with `AsyncWorld::spawn_empty()`.
18///
19/// Dropping the `AsyncEntity` **WILL NOT** despawn the corresponding entity in the synchronous world.
20/// Use `AsyncEntity::despawn` to despawn an entity asynchronously.
21#[derive(Debug)]
22pub struct AsyncEntity {
23	id: Entity,
24	world: AsyncWorld,
25}
26
27impl AsyncEntity {
28	pub(crate) fn new(id: Entity, world: AsyncWorld) -> Self {
29		Self { id, world }
30	}
31
32	/// Returns the underlying `Entity` being represented.
33	pub fn id(&self) -> Entity {
34		self.id
35	}
36
37	/// Returns a copy of the underlying `CommandQueueSender`.
38	pub fn sender(&self) -> CommandQueueSender {
39		self.world.sender()
40	}
41
42	/// Recursively despawns the represented entity.
43	pub async fn despawn(self) {
44		self.world.apply(despawn(self.id)).await;
45	}
46
47	/// Adds a `Bundle` of components to the entity. This will overwrite any previous value(s) of
48	/// the same component type.
49	pub async fn insert<B: Bundle>(&self, bundle: B) {
50		self.world.apply(insert(self.id, bundle)).await;
51	}
52
53	/// Removes a `Bundle` of components from the entity.
54	pub async fn remove<B: Bundle>(&self) {
55		self.world.apply(remove::<B>(self.id)).await;
56	}
57
58	/// Start waiting for the `Component` of a given type. Returns an `AsyncComponent` which can be further
59	/// waited to receive the value of the component.
60	///
61	/// `AsyncComponent::wait_for().await` is equivalent to
62	/// `AsyncComponent::start_waiting_for().await.wait().await`.
63	pub async fn start_waiting_for<C: Component + Clone>(&self) -> AsyncComponent<C> {
64		let (start_waiting_for, rx) = StartWaitingFor::component(self.id);
65		self.world.apply(start_waiting_for).await;
66		AsyncComponent(rx)
67	}
68
69	/// Wait for the `Component` of a given type. Returns the value of the component, once it exists
70	/// on the represented entity.
71	///
72	/// `AsyncComponent::wait_for().await` is equivalent to
73	/// `AsyncComponent::start_waiting_for().await.wait().await`.
74	pub async fn wait_for<C: Component + Clone>(&self) -> C {
75		self.start_waiting_for().await.wait().await
76	}
77
78	/// Insert the given `Component` of type `I` onto the entity, then immediately wait for a
79	/// component of type `WR` to be added to the entity. After one is received, this will then
80	/// remove the component of type `WR`.
81	pub async fn insert_wait_remove<I: Component, WR: Component + Clone>(
82		&self,
83		component: I,
84	) -> WR {
85		self.insert(component).await;
86		let wr = self.wait_for::<WR>().await;
87		self.remove::<WR>().await;
88		wr
89	}
90}
91
92/// Represents a `Component` being retrieved.
93///
94/// The easiest way to get an `AsyncComponent` is with `AsyncEntity::start_waiting_for()`.
95pub struct AsyncComponent<C: Component>(Receiver<C>);
96
97impl<C: Component> fmt::Debug for AsyncComponent<C> {
98	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99		write!(f, "AsyncComponent(..)")
100	}
101}
102
103impl<C: Component> AsyncComponent<C> {
104	/// Wait for the `Component` to exist, and retrieve its value.
105	pub async fn wait(self) -> C {
106		recv(self.0).await
107	}
108}
109
110pub(crate) struct SpawnAndSendId<B> {
111	bundle: B,
112	sender: Sender<Entity>,
113}
114
115impl SpawnAndSendId<()> {
116	pub(crate) fn new_empty() -> (Self, Receiver<Entity>) {
117		let (sender, receiver) = async_channel::bounded(1);
118		(Self { bundle: (), sender }, receiver)
119	}
120}
121
122impl<B: Bundle> SpawnAndSendId<B> {
123	pub(crate) fn new(bundle: B) -> (Self, Receiver<Entity>) {
124		let (sender, receiver) = async_channel::bounded(1);
125		(Self { bundle, sender }, receiver)
126	}
127}
128
129impl<B: Bundle> Command for SpawnAndSendId<B> {
130	fn apply(self, world: &mut World) {
131		let id = world.spawn(self.bundle).id();
132		if let Err(e @ TrySendError::Full(_)) = self.sender.try_send(id) {
133			let _: () = die(e);
134		}
135	}
136}
137
138#[cfg(test)]
139mod tests {
140	use crate::AsyncEcsPlugin;
141	use crate::AsyncWorld;
142	use bevy::prelude::*;
143	use bevy::tasks::AsyncComputeTaskPool;
144
145	#[derive(Default, Clone, Component)]
146	struct Translation(u8, u8);
147
148	#[derive(Default, Clone, Component)]
149	struct Scale(u8, u8);
150
151	#[derive(Default, Clone, Bundle)]
152	struct Transform {
153		translation: Translation,
154		scale: Scale,
155	}
156
157	#[test]
158	fn smoke() {
159		let mut app = App::new();
160		app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
161
162		let (sender, receiver) = async_channel::bounded(1);
163		let async_world = AsyncWorld::from_world(app.world_mut());
164
165		AsyncComputeTaskPool::get()
166			.spawn(async move {
167				let entity = async_world.spawn_empty().await;
168				sender.send(entity.id()).await.unwrap();
169			})
170			.detach();
171
172		let id = loop {
173			match receiver.try_recv() {
174				Ok(id) => break id,
175				Err(_) => app.update(),
176			}
177		};
178
179		assert!(app.world().get_entity(id).is_ok());
180	}
181
182	#[test]
183	fn named() {
184		let mut app = App::new();
185		app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
186
187		let (sender, receiver) = async_channel::bounded(1);
188		let async_world = AsyncWorld::from_world(app.world_mut());
189
190		AsyncComputeTaskPool::get()
191			.spawn(async move {
192				let entity = async_world.spawn_named("lol").await;
193				sender.send(entity.id).await.unwrap();
194			})
195			.detach();
196
197		let id = loop {
198			match receiver.try_recv() {
199				Ok(id) => break id,
200				Err(_) => app.update(),
201			}
202		};
203
204		let name = app.world().entity(id).get::<Name>().unwrap();
205		assert_eq!("lol", name.as_str());
206	}
207
208	#[test]
209	fn despawn() {
210		let mut app = App::new();
211		app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
212
213		let (sender, receiver) = async_channel::bounded(1);
214		let async_world = AsyncWorld::from_world(app.world_mut());
215		let id = app.world_mut().spawn_empty().id();
216
217		AsyncComputeTaskPool::get()
218			.spawn(async move {
219				let entity = async_world.entity(id);
220				entity.despawn().await;
221				sender.send(()).await.unwrap();
222			})
223			.detach();
224
225		loop {
226			match receiver.try_recv() {
227				Ok(_) => break,
228				Err(_) => app.update(),
229			}
230		}
231
232		assert!(app.world().get_entity(id).is_err());
233	}
234
235	#[test]
236	fn spawn() {
237		let mut app = App::new();
238		app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
239
240		let (sender, receiver) = async_channel::bounded(1);
241		let async_world = AsyncWorld::from_world(app.world_mut());
242
243		AsyncComputeTaskPool::get()
244			.spawn(async move {
245				let entity = async_world
246					.spawn(Transform {
247						translation: Translation(2, 3),
248						scale: Scale(1, 1),
249					})
250					.await;
251				sender.send(entity.id).await.unwrap();
252			})
253			.detach();
254
255		let id = loop {
256			match receiver.try_recv() {
257				Ok(id) => break id,
258				Err(_) => app.update(),
259			}
260		};
261
262		let translation = app.world().get::<Translation>(id).unwrap();
263		assert_eq!(2, translation.0);
264		assert_eq!(3, translation.1);
265		let scale = app.world().get::<Scale>(id).unwrap();
266		assert_eq!(1, scale.0);
267		assert_eq!(1, scale.1);
268	}
269
270	#[test]
271	fn insert() {
272		let mut app = App::new();
273		app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
274
275		let (sender, receiver) = async_channel::bounded(1);
276		let async_world = AsyncWorld::from_world(app.world_mut());
277
278		AsyncComputeTaskPool::get()
279			.spawn(async move {
280				let entity = async_world.spawn_empty().await;
281				sender.send(entity.id).await.unwrap();
282				entity
283					.insert(Transform {
284						translation: Translation(2, 3),
285						scale: Scale(1, 1),
286					})
287					.await;
288			})
289			.detach();
290
291		let id = loop {
292			match receiver.try_recv() {
293				Ok(id) => break id,
294				Err(_) => app.update(),
295			}
296		};
297		app.update();
298
299		let translation = app.world().get::<Translation>(id).unwrap();
300		assert_eq!(2, translation.0);
301		assert_eq!(3, translation.1);
302		let scale = app.world().get::<Scale>(id).unwrap();
303		assert_eq!(1, scale.0);
304		assert_eq!(1, scale.1);
305	}
306
307	#[test]
308	fn remove() {
309		let mut app = App::new();
310		app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
311
312		let async_world = AsyncWorld::from_world(app.world_mut());
313		let id = app
314			.world_mut()
315			.spawn(Transform {
316				translation: Translation(3, 4),
317				scale: Scale(1, 1),
318			})
319			.id();
320
321		AsyncComputeTaskPool::get()
322			.spawn(async move {
323				async_world.entity(id).remove::<Transform>().await;
324			})
325			.detach();
326		app.update();
327
328		assert!(app.world().get::<Translation>(id).is_none());
329		assert!(app.world().get::<Scale>(id).is_none());
330	}
331
332	#[test]
333	fn insert_wait_remove() {
334		let mut app = App::new();
335		app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
336
337		let (value_tx, value_rx) = async_channel::bounded(1);
338		let async_world = AsyncWorld::from_world(app.world_mut());
339		let id = app.world_mut().spawn_empty().id();
340
341		AsyncComputeTaskPool::get()
342			.spawn(async move {
343				let scale: Scale = async_world.entity(id).insert_wait_remove(Scale(6, 7)).await;
344				value_tx.send(scale).await.unwrap();
345			})
346			.detach();
347
348		let value = loop {
349			match value_rx.try_recv() {
350				Ok(value) => break value,
351				Err(_) => app.update(),
352			}
353		};
354		app.update();
355
356		assert_eq!(6, value.0);
357		assert_eq!(7, value.1);
358		assert!(app.world().entity(id).get::<Scale>().is_none());
359	}
360}