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};
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 self.sender.try_send(id).unwrap_or_else(die);
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use crate::{AsyncEcsPlugin, AsyncWorld};
134 use bevy::prelude::*;
135 use bevy::tasks::AsyncComputeTaskPool;
136
137 #[derive(Default, Clone, Component)]
138 struct Translation(u8, u8);
139
140 #[derive(Default, Clone, Component)]
141 struct Scale(u8, u8);
142
143 #[derive(Default, Clone, Bundle)]
144 struct Transform {
145 translation: Translation,
146 scale: Scale,
147 }
148
149 #[test]
150 fn smoke() {
151 let mut app = App::new();
152 app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
153
154 let (sender, receiver) = async_channel::bounded(1);
155 let async_world = AsyncWorld::from_world(app.world_mut());
156
157 AsyncComputeTaskPool::get()
158 .spawn(async move {
159 let entity = async_world.spawn_empty().await;
160 sender.send(entity.id()).await.unwrap();
161 })
162 .detach();
163
164 let id = loop {
165 match receiver.try_recv() {
166 Ok(id) => break id,
167 Err(_) => app.update(),
168 }
169 };
170
171 assert!(app.world().get_entity(id).is_ok());
172 }
173
174 #[test]
175 fn named() {
176 let mut app = App::new();
177 app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
178
179 let (sender, receiver) = async_channel::bounded(1);
180 let async_world = AsyncWorld::from_world(app.world_mut());
181
182 AsyncComputeTaskPool::get()
183 .spawn(async move {
184 let entity = async_world.spawn_named("lol").await;
185 sender.send(entity.id).await.unwrap();
186 })
187 .detach();
188
189 let id = loop {
190 match receiver.try_recv() {
191 Ok(id) => break id,
192 Err(_) => app.update(),
193 }
194 };
195
196 let name = app.world().entity(id).get::<Name>().unwrap();
197 assert_eq!("lol", name.as_str());
198 }
199
200 #[test]
201 fn despawn() {
202 let mut app = App::new();
203 app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
204
205 let (sender, receiver) = async_channel::bounded(1);
206 let async_world = AsyncWorld::from_world(app.world_mut());
207 let id = app.world_mut().spawn_empty().id();
208
209 AsyncComputeTaskPool::get()
210 .spawn(async move {
211 let entity = async_world.entity(id);
212 entity.despawn().await;
213 sender.send(()).await.unwrap();
214 })
215 .detach();
216
217 loop {
218 match receiver.try_recv() {
219 Ok(_) => break,
220 Err(_) => app.update(),
221 }
222 }
223
224 assert!(app.world().get_entity(id).is_err());
225 }
226
227 #[test]
228 fn spawn() {
229 let mut app = App::new();
230 app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
231
232 let (sender, receiver) = async_channel::bounded(1);
233 let async_world = AsyncWorld::from_world(app.world_mut());
234
235 AsyncComputeTaskPool::get()
236 .spawn(async move {
237 let entity = async_world
238 .spawn(Transform {
239 translation: Translation(2, 3),
240 scale: Scale(1, 1),
241 })
242 .await;
243 sender.send(entity.id).await.unwrap();
244 })
245 .detach();
246
247 let id = loop {
248 match receiver.try_recv() {
249 Ok(id) => break id,
250 Err(_) => app.update(),
251 }
252 };
253
254 let translation = app.world().get::<Translation>(id).unwrap();
255 assert_eq!(2, translation.0);
256 assert_eq!(3, translation.1);
257 let scale = app.world().get::<Scale>(id).unwrap();
258 assert_eq!(1, scale.0);
259 assert_eq!(1, scale.1);
260 }
261
262 #[test]
263 fn insert() {
264 let mut app = App::new();
265 app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
266
267 let (sender, receiver) = async_channel::bounded(1);
268 let async_world = AsyncWorld::from_world(app.world_mut());
269
270 AsyncComputeTaskPool::get()
271 .spawn(async move {
272 let entity = async_world.spawn_empty().await;
273 sender.send(entity.id).await.unwrap();
274 entity
275 .insert(Transform {
276 translation: Translation(2, 3),
277 scale: Scale(1, 1),
278 })
279 .await;
280 })
281 .detach();
282
283 let id = loop {
284 match receiver.try_recv() {
285 Ok(id) => break id,
286 Err(_) => app.update(),
287 }
288 };
289 app.update();
290
291 let translation = app.world().get::<Translation>(id).unwrap();
292 assert_eq!(2, translation.0);
293 assert_eq!(3, translation.1);
294 let scale = app.world().get::<Scale>(id).unwrap();
295 assert_eq!(1, scale.0);
296 assert_eq!(1, scale.1);
297 }
298
299 #[test]
300 fn remove() {
301 let mut app = App::new();
302 app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
303
304 let async_world = AsyncWorld::from_world(app.world_mut());
305 let id = app
306 .world_mut()
307 .spawn(Transform {
308 translation: Translation(3, 4),
309 scale: Scale(1, 1),
310 })
311 .id();
312
313 AsyncComputeTaskPool::get()
314 .spawn(async move {
315 async_world.entity(id).remove::<Transform>().await;
316 })
317 .detach();
318 app.update();
319
320 assert!(app.world().get::<Translation>(id).is_none());
321 assert!(app.world().get::<Scale>(id).is_none());
322 }
323
324 #[test]
325 fn insert_wait_remove() {
326 let mut app = App::new();
327 app.add_plugins((MinimalPlugins, AsyncEcsPlugin));
328
329 let (value_tx, value_rx) = async_channel::bounded(1);
330 let async_world = AsyncWorld::from_world(app.world_mut());
331 let id = app.world_mut().spawn_empty().id();
332
333 AsyncComputeTaskPool::get()
334 .spawn(async move {
335 let scale: Scale = async_world.entity(id).insert_wait_remove(Scale(6, 7)).await;
336 value_tx.send(scale).await.unwrap();
337 })
338 .detach();
339
340 let value = loop {
341 match value_rx.try_recv() {
342 Ok(value) => break value,
343 Err(_) => app.update(),
344 }
345 };
346 app.update();
347
348 assert_eq!(6, value.0);
349 assert_eq!(7, value.1);
350 assert!(app.world().entity(id).get::<Scale>().is_none());
351 }
352}