#bevy-ecs #bevy #async #async-parallel #async-task

bevy-async-ecs

Asynchronous interface for Bevy ECS

9 releases (5 breaking)

0.6.1 Oct 30, 2024
0.6.0 Aug 13, 2024
0.5.1 Jun 4, 2024
0.5.0 Feb 18, 2024
0.1.0 Dec 1, 2023

#245 in Game dev

Download history 42/week @ 2024-07-29 123/week @ 2024-08-12 10/week @ 2024-08-26 21/week @ 2024-09-02 18/week @ 2024-09-16 27/week @ 2024-09-23 28/week @ 2024-09-30 23/week @ 2024-10-07 28/week @ 2024-10-14 5/week @ 2024-10-21 138/week @ 2024-10-28 47/week @ 2024-11-04 336/week @ 2024-11-11

532 downloads per month
Used in 4 crates (3 directly)

MIT license

51KB
1K SLoC

🔄 Bevy Async ECS

License: MIT Doc Crate Bevy tracking

What is Bevy Async ECS?

Bevy Async ECS is an asynchronous interface to the standard Bevy World. It aims to be simple and intuitive to use for those familiar with Bevy's ECS.

AsyncWorld

AsyncWorld is the entrypoint for all further asynchronous manipulation of the world. It can only be created using the FromWorld trait implementation. It should be driven by an executor running parallel with the main Bevy app (this can either be one of the TaskPools or a blocking executor running on another thread).

Internally, the AsyncWorld simply wraps an MPSC channel sender. As such, it can be cheaply cloned and further sent to separate threads or tasks. This means that all operations on the AsyncWorld are processed in FIFO order. However, there are no ordering guarantees between AsyncWorlds or any derivatives sharing the same internal channel sender, or any AsyncWorlds constructed separately.

It is important to note that Bevy is still running and mutating the world while the async tasks run! Assume that the world could have been mutated between any asynchronous call. However, there are several ways to ensure that multiple commands are applied together, without mutation of the world in between:

  • Construct a vanilla Bevy CommandQueue, and send it to the Bevy World with CommandQueueSender::send_queue()
  • Use the queue builder provided by the AsyncWorld via AsyncWorld::start_queue()

Basic example

use bevy::prelude::*;
use bevy::tasks::AsyncComputeTaskPool;
use bevy_async_ecs::*;

// vanilla Bevy system
fn print_names(query: Query<(Entity, &Name)>) {
	for (id, name) in query.iter() {
		info!("entity {:?} has name '{}'", id, name);
	}
}

fn main() {
	App::new()
		.add_plugins((DefaultPlugins, AsyncEcsPlugin))
		.add_systems(Startup, |world: &mut World| {
			let async_world = AsyncWorld::from_world(world);
			let fut = async move {
				let print_names = async_world.register_system(print_names).await;

				let entity = async_world.spawn_named("Frank").await;
				print_names.run().await;
				entity.despawn().await;
			};
			AsyncComputeTaskPool::get().spawn(fut).detach();
		})
		.run();
}

Wasm Support

bevy-async-ecs fully supports running in a web environment. Run the examples in your browser:

# One-time setup
rustup target install wasm32-unknown-unknown
cargo install wasm-server-runner

# Run examples
CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasm-server-runner cargo run --target wasm32-unknown-unknown --example end_to_end

Multithreaded

bevy-async-ecs does not explicitly require the multi-threaded feature (though all the tests and non-browser examples do). However, due to its asynchronous nature, this library inherently requires a multithreaded environment. In a web environment, the browser provides this for us. On native platforms, the multi-threaded feature will likely have to be enabled to prevent the app from deadlocking.

Most recently compatible versions

bevy bevy-async-ecs
0.14 0.6.1
0.13 0.5.1
0.12 0.4.1
0.11 N/A

Dependencies

~13MB
~218K SLoC