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#[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 pub fn id(&self) -> Entity {
29 self.id
30 }
31
32 pub fn sender(&self) -> CommandQueueSender {
34 self.world.sender()
35 }
36
37 pub async fn despawn(self) {
39 self.world.apply(despawn(self.id)).await;
40 }
41
42 pub async fn insert<B: Bundle>(&self, bundle: B) {
45 self.world.apply(insert(self.id, bundle)).await;
46 }
47
48 pub async fn remove<B: Bundle>(&self) {
50 self.world.apply(remove::<B>(self.id)).await;
51 }
52
53 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 pub async fn wait_for<C: Component + Clone>(&self) -> C {
70 self.start_waiting_for().await.wait().await
71 }
72
73 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
87pub 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 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}