use crate::command::{BoxedCommand, CommandQueueBuilder, CommandQueueReceiver, CommandQueueSender};
use crate::entity::{AsyncEntity, SpawnAndSendId};
use crate::system::{AsyncIOSystem, AsyncSystem};
use crate::util::{insert_resource, remove_resource, trigger_targets};
use crate::wait_for::StartWaitingFor;
use crate::{die, recv, CowStr};
use async_channel::Receiver;
use bevy_ecs::observer::TriggerTargets;
use bevy_ecs::prelude::*;
use bevy_ecs::system::RunSystemOnce;
use std::fmt;
#[derive(Clone, Debug)]
pub struct AsyncWorld(CommandQueueSender);
impl AsyncWorld {
pub fn sender(&self) -> CommandQueueSender {
self.0.clone()
}
pub async fn apply<C: Command>(&self, command: C) {
self.0.send_single(BoxedCommand::new(command)).await
}
pub fn start_queue(&self) -> CommandQueueBuilder {
CommandQueueBuilder::new(self.sender())
}
pub async fn run_system<M>(self, system: impl IntoSystem<(), (), M> + Send + 'static) {
self.apply(|world: &mut World| {
_ = world.run_system_once(system);
})
.await
}
pub async fn register_system<M>(
&self,
system: impl IntoSystem<(), (), M> + Send,
) -> AsyncSystem {
let system = Box::new(IntoSystem::into_system(system));
AsyncSystem::new(system, self.clone()).await
}
pub async fn register_io_system<I: Send + 'static, O: Send + 'static, M>(
&self,
system: impl IntoSystem<In<I>, O, M> + Send,
) -> AsyncIOSystem<I, O> {
AsyncIOSystem::new(system, self.clone()).await
}
pub fn entity(&self, id: Entity) -> AsyncEntity {
AsyncEntity::new(id, self.clone())
}
pub async fn spawn_empty(&self) -> AsyncEntity {
let (command, receiver) = SpawnAndSendId::new_empty();
self.apply(command).await;
let id = recv(receiver).await;
AsyncEntity::new(id, self.clone())
}
pub async fn spawn<B: Bundle>(&self, bundle: B) -> AsyncEntity {
let (command, receiver) = SpawnAndSendId::new(bundle);
self.apply(command).await;
let id = recv(receiver).await;
AsyncEntity::new(id, self.clone())
}
pub async fn spawn_named(&self, name: impl Into<CowStr> + Send) -> AsyncEntity {
self.spawn(Name::new(name)).await
}
pub async fn insert_resource<R: Resource>(&self, resource: R) {
self.apply(insert_resource(resource)).await;
}
pub async fn remove_resource<R: Resource>(&self) {
self.apply(remove_resource::<R>()).await;
}
pub async fn start_waiting_for_resource<R: Resource + Clone>(&self) -> AsyncResource<R> {
let (start_waiting_for, rx) = StartWaitingFor::resource();
self.apply(start_waiting_for).await;
AsyncResource(rx)
}
pub async fn wait_for_resource<R: Resource + Clone>(&self) -> R {
self.start_waiting_for_resource().await.wait().await
}
pub async fn send_event<E: Event>(&self, event: E) {
self.apply(SendEvent(event)).await;
}
pub async fn start_waiting_for_events<E: Event + Clone>(&self) -> AsyncEvents<E> {
let (start_waiting_for, rx) = StartWaitingFor::events();
self.apply(start_waiting_for).await;
AsyncEvents(rx)
}
pub async fn wait_for_event<E: Event + Clone>(&self) -> E {
self.start_waiting_for_events().await.wait().await
}
pub async fn trigger<E: Event>(&self, event: E) {
self.trigger_targets(event, ()).await;
}
pub async fn trigger_targets<E: Event, T: TriggerTargets + Send + Sync + 'static>(
&self,
event: E,
targets: T,
) {
self.apply(trigger_targets(event, targets)).await;
}
}
impl From<CommandQueueSender> for AsyncWorld {
fn from(sender: CommandQueueSender) -> Self {
Self(sender)
}
}
impl FromWorld for AsyncWorld {
fn from_world(world: &mut World) -> Self {
let (sender, receiver) = async_channel::unbounded();
world.spawn((
CommandQueueReceiver::new(receiver),
Name::new("CommandQueueReceiver"),
));
CommandQueueSender::new(sender).into()
}
}
pub struct AsyncResource<R: Resource>(Receiver<R>);
impl<R: Resource> fmt::Debug for AsyncResource<R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AsyncResource(..)")
}
}
impl<R: Resource> AsyncResource<R> {
pub async fn wait(self) -> R {
recv(self.0).await
}
}
struct SendEvent<E: Event>(E);
impl<E: Event> Command for SendEvent<E> {
fn apply(self, world: &mut World) {
world
.send_event(self.0)
.ok_or("failed to send event")
.unwrap_or_else(die);
}
}
pub struct AsyncEvents<E: Event>(Receiver<E>);
impl<E: Event> fmt::Debug for AsyncEvents<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AsyncEvents(..)")
}
}
impl<E: Event> AsyncEvents<E> {
pub async fn wait(&self) -> E {
recv(self.0.clone()).await
}
}