bevy_async_ecs/
entity.rs

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