bevy_async_ecs/
entity.rs

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