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, trigger_targets};
5use crate::wait_for::StartWaitingFor;
6use crate::{die, recv, CowStr};
7use async_channel::Receiver;
8use bevy_ecs::observer::TriggerTargets;
9use bevy_ecs::prelude::*;
10use bevy_ecs::system::RunSystemOnce;
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	/// Run a [`System`] once.
50	pub async fn run_system<M>(self, system: impl IntoSystem<(), (), M> + Send + 'static) {
51		self.apply(|world: &mut World| {
52			_ = world.run_system_once(system);
53		})
54		.await
55	}
56
57	/// Registers a `System` and returns an `AsyncSystem` that can be used to run the system on demand.
58	pub async fn register_system<M>(
59		&self,
60		system: impl IntoSystem<(), (), M> + Send,
61	) -> AsyncSystem {
62		let system = Box::new(IntoSystem::into_system(system));
63		AsyncSystem::new(system, self.clone()).await
64	}
65
66	/// Registers a `System` and returns an `AsyncIOSystem` that can be used to run the system on demand
67	/// while supplying an input value and receiving an output value.
68	pub async fn register_io_system<I: Send + 'static, O: Send + 'static, M>(
69		&self,
70		system: impl IntoSystem<In<I>, O, M> + Send,
71	) -> AsyncIOSystem<I, O> {
72		AsyncIOSystem::new(system, self.clone()).await
73	}
74
75	/// Constructs an `AsyncEntity` for the given `Entity`. If the entity does not exist, any operation
76	/// performed on it will panic.
77	pub fn entity(&self, id: Entity) -> AsyncEntity {
78		AsyncEntity::new(id, self.clone())
79	}
80
81	/// Spawns a new `Entity` and returns an `AsyncEntity` that represents it, which can be used
82	/// to further manipulate the entity.
83	pub async fn spawn_empty(&self) -> AsyncEntity {
84		let (command, receiver) = SpawnAndSendId::new_empty();
85		self.apply(command).await;
86		let id = recv(receiver).await;
87		AsyncEntity::new(id, self.clone())
88	}
89
90	/// Spawns a new `Entity` with the given `Bundle` and returns an `AsyncEntity` that represents it,
91	/// which can be used to further manipulate the entity.
92	pub async fn spawn<B: Bundle>(&self, bundle: B) -> AsyncEntity {
93		let (command, receiver) = SpawnAndSendId::new(bundle);
94		self.apply(command).await;
95		let id = recv(receiver).await;
96		AsyncEntity::new(id, self.clone())
97	}
98
99	/// Spawns a new `Entity` and returns an `AsyncEntity` that represents it, which can be used
100	/// to further manipulate the entity. This function attaches a bevy `Name` component with the given
101	/// value.
102	pub async fn spawn_named(&self, name: impl Into<CowStr> + Send) -> AsyncEntity {
103		self.spawn(Name::new(name)).await
104	}
105
106	/// Inserts a new resource or updates an existing resource with the given value.
107	pub async fn insert_resource<R: Resource>(&self, resource: R) {
108		self.apply(insert_resource(resource)).await;
109	}
110
111	/// Removes the resource of a given type, if it exists.
112	pub async fn remove_resource<R: Resource>(&self) {
113		self.apply(remove_resource::<R>()).await;
114	}
115
116	/// Start waiting for the `Resource` of a given type. Returns an `AsyncResource` which can be further
117	/// waited to receive the value of the resource.
118	///
119	/// `AsyncWorld::wait_for_resource().await` is equivalent to
120	/// `AsyncWorld::start_waiting_for_resource().await.wait().await`.
121	pub async fn start_waiting_for_resource<R: Resource + Clone>(&self) -> AsyncResource<R> {
122		let (start_waiting_for, rx) = StartWaitingFor::resource();
123		self.apply(start_waiting_for).await;
124		AsyncResource(rx)
125	}
126
127	/// Wait for the `Resource` of a given type. Returns the value of the resource, once it exists.
128	///
129	/// `AsyncWorld::wait_for_resource().await` is equivalent to
130	/// `AsyncWorld::start_waiting_for_resource().await.wait().await`.
131	pub async fn wait_for_resource<R: Resource + Clone>(&self) -> R {
132		self.start_waiting_for_resource().await.wait().await
133	}
134
135	/// Send an `Event` to the bevy world.
136	pub async fn send_event<E: Event>(&self, event: E) {
137		self.apply(SendEvent(event)).await;
138	}
139
140	/// Start listening for `Event`s coming from the main bevy world.
141	/// Returns an `AsyncEvents` which can be further waited to receive these events.
142	///
143	/// `AsyncWorld::wait_for_event().await` is equivalent to
144	/// `AsyncWorld::start_waiting_for_events().await.wait().await`.
145	pub async fn start_waiting_for_events<E: Event + Clone>(&self) -> AsyncEvents<E> {
146		let (start_waiting_for, rx) = StartWaitingFor::events();
147		self.apply(start_waiting_for).await;
148		AsyncEvents(rx)
149	}
150
151	/// Wait for the `Event` of a given type. Returns the value of the event, once it is received.
152	///
153	/// `AsyncWorld::wait_for_event().await` is equivalent to
154	/// `AsyncWorld::start_waiting_for_events().await.wait().await`.
155	pub async fn wait_for_event<E: Event + Clone>(&self) -> E {
156		self.start_waiting_for_events().await.wait().await
157	}
158
159	/// Triggers the given [`Event`], which will run any [`Observer`]s watching for it.
160	pub async fn trigger<E: Event>(&self, event: E) {
161		self.trigger_targets(event, ()).await;
162	}
163
164	/// Triggers the given [`Event`] for the given `targets`, which will run any [`Observer`]s watching for it.
165	pub async fn trigger_targets<E: Event, T: TriggerTargets + Send + Sync + 'static>(
166		&self,
167		event: E,
168		targets: T,
169	) {
170		self.apply(trigger_targets(event, targets)).await;
171	}
172}
173
174impl From<CommandQueueSender> for AsyncWorld {
175	fn from(sender: CommandQueueSender) -> Self {
176		Self(sender)
177	}
178}
179
180impl FromWorld for AsyncWorld {
181	fn from_world(world: &mut World) -> Self {
182		let (sender, receiver) = async_channel::unbounded();
183		world.spawn((
184			CommandQueueReceiver::new(receiver),
185			Name::new("CommandQueueReceiver"),
186		));
187		CommandQueueSender::new(sender).into()
188	}
189}
190
191/// Represents a `Resource` being retrieved.
192///
193/// The easiest way to get an `AsyncResource` is with `AsyncWorld::start_waiting_for_resource()`.
194pub struct AsyncResource<R: Resource>(Receiver<R>);
195
196impl<R: Resource> fmt::Debug for AsyncResource<R> {
197	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198		write!(f, "AsyncResource(..)")
199	}
200}
201
202impl<R: Resource> AsyncResource<R> {
203	/// Wait for the `Resource` to exist, and retrieve its value.
204	pub async fn wait(self) -> R {
205		recv(self.0).await
206	}
207}
208
209struct SendEvent<E: Event>(E);
210
211impl<E: Event> Command for SendEvent<E> {
212	fn apply(self, world: &mut World) {
213		world
214			.send_event(self.0)
215			.ok_or("failed to send event")
216			.unwrap_or_else(die);
217	}
218}
219
220/// Represents Bevy `Event`s being received asynchronously
221///
222/// The easiest way to get an `AsyncEvents` is with `AsyncWorld::start_waiting_for_events()`.
223pub struct AsyncEvents<E: Event>(Receiver<E>);
224
225impl<E: Event> fmt::Debug for AsyncEvents<E> {
226	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227		write!(f, "AsyncEvents(..)")
228	}
229}
230
231impl<E: Event> AsyncEvents<E> {
232	/// Wait for an `Event` to be received from the vanilla Bevy world. This function can be called repeatedly
233	/// to get more events as they are received.
234	pub async fn wait(&self) -> E {
235		recv(self.0.clone()).await
236	}
237}