bevy_async_ecs/
world.rs

1use crate::command::{BoxedCommand, CommandQueueBuilder, CommandQueueReceiver, CommandQueueSender};
2use crate::entity::{AsyncEntity, SpawnAndSendId};
3use crate::system::{AsyncIOSystem, AsyncSystem};
4use crate::util::{insert_resource, remove_resource};
5use crate::wait_for::StartWaitingFor;
6use crate::{die, recv, CowStr};
7use async_channel::Receiver;
8use bevy_ecs::prelude::*;
9use std::fmt;
10
11/// Exposes asynchronous access to the Bevy ECS `World`.
12///
13/// The easiest way to get an `AsyncWorld` is with `AsyncWorld::from_world()`.
14///
15/// ## Commands
16/// Apply any `Command` asynchronously with `AsyncWorld::apply_command`.
17///
18/// ## Systems
19/// Just like their synchronous variants, asynchronous `System`s must be registered
20/// before they can be used. Systems can optionally accept and return values asynchronously
21/// if they are registered with `AsyncWorld::register_io_system`.
22///
23/// ## Entities
24/// Spawn entities with the `AsyncWorld::spawn_*` family.
25///
26/// ## Resources
27/// Insert, remove, and wait for resources to exist.
28#[derive(Clone, Debug)]
29pub struct AsyncWorld(CommandQueueSender);
30
31impl AsyncWorld {
32	/// Returns a copy of the underlying `CommandQueueSender`.
33	pub fn sender(&self) -> CommandQueueSender {
34		self.0.clone()
35	}
36
37	/// Applies the given `Command` to the world.
38	pub async fn apply<C: Command>(&self, command: C) {
39		self.0.send_single(BoxedCommand::new(command)).await
40	}
41
42	/// Starts building a `CommandQueue`.
43	pub fn start_queue(&self) -> CommandQueueBuilder {
44		CommandQueueBuilder::new(self.sender())
45	}
46
47	/// Registers a `System` and returns an `AsyncSystem` that can be used to run the system on demand.
48	pub async fn register_system<M>(
49		&self,
50		system: impl IntoSystem<(), (), M> + Send,
51	) -> AsyncSystem {
52		let system = Box::new(IntoSystem::into_system(system));
53		AsyncSystem::new(system, self.clone()).await
54	}
55
56	/// Registers a `System` and returns an `AsyncIOSystem` that can be used to run the system on demand
57	/// while supplying an input value and receiving an output value.
58	pub async fn register_io_system<I: Send + 'static, O: Send + 'static, M>(
59		&self,
60		system: impl IntoSystem<In<I>, O, M> + Send,
61	) -> AsyncIOSystem<I, O> {
62		AsyncIOSystem::new(system, self.clone()).await
63	}
64
65	/// Constructs an `AsyncEntity` for the given `Entity`. If the entity does not exist, any operation
66	/// performed on it will panic.
67	pub fn entity(&self, id: Entity) -> AsyncEntity {
68		AsyncEntity::new(id, self.clone())
69	}
70
71	/// Spawns a new `Entity` and returns an `AsyncEntity` that represents it, which can be used
72	/// to further manipulate the entity.
73	pub async fn spawn_empty(&self) -> AsyncEntity {
74		let (command, receiver) = SpawnAndSendId::new_empty();
75		self.apply(command).await;
76		let id = recv(receiver).await;
77		AsyncEntity::new(id, self.clone())
78	}
79
80	/// Spawns a new `Entity` with the given `Bundle` and returns an `AsyncEntity` that represents it,
81	/// which can be used to further manipulate the entity.
82	pub async fn spawn<B: Bundle>(&self, bundle: B) -> AsyncEntity {
83		let (command, receiver) = SpawnAndSendId::new(bundle);
84		self.apply(command).await;
85		let id = recv(receiver).await;
86		AsyncEntity::new(id, self.clone())
87	}
88
89	/// Spawns a new `Entity` and returns an `AsyncEntity` that represents it, which can be used
90	/// to further manipulate the entity. This function attaches a bevy `Name` component with the given
91	/// value.
92	pub async fn spawn_named(&self, name: impl Into<CowStr> + Send) -> AsyncEntity {
93		self.spawn(Name::new(name)).await
94	}
95
96	/// Inserts a new resource or updates an existing resource with the given value.
97	pub async fn insert_resource<R: Resource>(&self, resource: R) {
98		self.apply(insert_resource(resource)).await;
99	}
100
101	/// Removes the resource of a given type, if it exists.
102	pub async fn remove_resource<R: Resource>(&self) {
103		self.apply(remove_resource::<R>()).await;
104	}
105
106	/// Start waiting for the `Resource` of a given type. Returns an `AsyncResource` which can be further
107	/// waited to receive the value of the resource.
108	///
109	/// `AsyncWorld::wait_for_resource().await` is equivalent to
110	/// `AsyncWorld::start_waiting_for_resource().await.wait().await`.
111	pub async fn start_waiting_for_resource<R: Resource + Clone>(&self) -> AsyncResource<R> {
112		let (start_waiting_for, rx) = StartWaitingFor::resource();
113		self.apply(start_waiting_for).await;
114		AsyncResource(rx)
115	}
116
117	/// Wait for the `Resource` of a given type. Returns the value of the resource, once it exists.
118	///
119	/// `AsyncWorld::wait_for_resource().await` is equivalent to
120	/// `AsyncWorld::start_waiting_for_resource().await.wait().await`.
121	pub async fn wait_for_resource<R: Resource + Clone>(&self) -> R {
122		self.start_waiting_for_resource().await.wait().await
123	}
124
125	/// Send an `Event` to the bevy world.
126	pub async fn send_event<E: Event>(&self, event: E) {
127		self.apply(SendEvent(event)).await;
128	}
129
130	/// Start listening for `Event`s coming from the main bevy world.
131	/// Returns an `AsyncEvents` which can be further waited to receive these events.
132	///
133	/// `AsyncWorld::wait_for_event().await` is equivalent to
134	/// `AsyncWorld::start_waiting_for_events().await.wait().await`.
135	pub async fn start_waiting_for_events<E: Event + Clone>(&self) -> AsyncEvents<E> {
136		let (start_waiting_for, rx) = StartWaitingFor::events();
137		self.apply(start_waiting_for).await;
138		AsyncEvents(rx)
139	}
140
141	/// Wait for the `Event` of a given type. Returns the value of the event, once it is received.
142	///
143	/// `AsyncWorld::wait_for_event().await` is equivalent to
144	/// `AsyncWorld::start_waiting_for_events().await.wait().await`.
145	pub async fn wait_for_event<E: Event + Clone>(&self) -> E {
146		self.start_waiting_for_events().await.wait().await
147	}
148}
149
150impl From<CommandQueueSender> for AsyncWorld {
151	fn from(sender: CommandQueueSender) -> Self {
152		Self(sender)
153	}
154}
155
156impl FromWorld for AsyncWorld {
157	fn from_world(world: &mut World) -> Self {
158		let (sender, receiver) = async_channel::unbounded();
159		world.spawn((
160			CommandQueueReceiver::new(receiver),
161			Name::new("CommandQueueReceiver"),
162		));
163		CommandQueueSender::new(sender).into()
164	}
165}
166
167/// Represents a `Resource` being retrieved.
168///
169/// The easiest way to get an `AsyncResource` is with `AsyncWorld::start_waiting_for_resource()`.
170pub struct AsyncResource<R: Resource>(Receiver<R>);
171
172impl<R: Resource> fmt::Debug for AsyncResource<R> {
173	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174		write!(f, "AsyncResource(..)")
175	}
176}
177
178impl<R: Resource> AsyncResource<R> {
179	/// Wait for the `Resource` to exist, and retrieve its value.
180	pub async fn wait(self) -> R {
181		recv(self.0).await
182	}
183}
184
185struct SendEvent<E: Event>(E);
186
187impl<E: Event> Command for SendEvent<E> {
188	fn apply(self, world: &mut World) {
189		world
190			.send_event(self.0)
191			.ok_or("failed to send event")
192			.unwrap_or_else(die);
193	}
194}
195
196/// Represents Bevy `Event`s being received asynchronously
197///
198/// The easiest way to get an `AsyncEvents` is with `AsyncWorld::start_waiting_for_events()`.
199pub struct AsyncEvents<E: Event>(Receiver<E>);
200
201impl<E: Event> fmt::Debug for AsyncEvents<E> {
202	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203		write!(f, "AsyncEvents(..)")
204	}
205}
206
207impl<E: Event> AsyncEvents<E> {
208	/// Wait for an `Event` to be received from the vanilla Bevy world. This function can be called repeatedly
209	/// to get more events as they are received.
210	pub async fn wait(&self) -> E {
211		recv(self.0.clone()).await
212	}
213}