bevyengine / bevyengine/bevy

Async EventWriter

Open
#8,983 1 comment 1 reaction 0 assignees View on GitHub
A-ECS A-Tasks C-Feature
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## What problem does this solve or what need does it fill?

There is currently no ergonomic way to use the results of an async task.
An example use case might be sending a web request to check the game leaderboards and displaying them when the request returns.

## What solution would you like?

I am proposing an `AsyncEventWriter : SystemParam` which behaves similar to a regular `EventWriter` except that it has `'static` lifetime so it can be sent to a long lived thread. The other difference is that writing events would be async and fallible (it would fail if the underlying resource had been removed from the world).

The writer would use a channel (from async_channel which is already a dependency) and this would be polled every frame (in a configurable system set?) and events forwarded to a regular `EventWriter`.

Usage would look like

```rust
pub struct LeaderboardPlugin;

impl Plugin for LeaderboardPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app
.add_async_event::()
.add_startup_system(load_leaderboard_data)
.add_system(hydrate_leaderboard);
}
}

fn load_leaderboard_data(writer : AsyncEventWriter) {
let task_pool = IoTaskPool::get();
task_pool
.spawn(async move {
let data_event = get_leaderboard_data().await;
writer.send_async(data_event).await.expect("Leaderboard event channel closed prematurely");
})
.detach();
}

fn hydrate_leaderboard(mut events: EventReader){
for ev in events.into_iter(){
todo!()
}
}

```

## What alternative(s) have you considered?

This could easily be a third party plugin but you would have to do something like `.add_plugin(AsyncEventPlugin::::default())` instead of the slightly nicer `.add_async_event::()`

## Questions

- Should it be possible to configure the system set in which the channel is polled and the events are transferred? What should the default be?
- Should `send_async()` take `&self` which is all that's needed or `&mut self` to mirror the method on `EventWriter`
- Should the underlying channel be bounded or unbounded? If bounded, what size? Should this be configurable?

## Additional context

I have a working version of this that I'm happy to contribute if it's considered worthwhile.

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing EventWriter and SystemParam APIs, then inspect how async_channel and IoTaskPool are used in the project. The issue leaves channel bounds, send_async mutability, polling placement, and the add_async_event API unresolved; done would require settling those design questions and implementing the proposed async event flow.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.