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