From 7c65ba96bb499e980499e7c71917d6fb82a78385 Mon Sep 17 00:00:00 2001 From: Matt Hunzinger Date: Sat, 7 Dec 2024 12:07:32 -0500 Subject: [PATCH] feat: add support for reactive Bevy desktop apps --- Cargo.lock | 1 + Cargo.toml | 3 ++- examples/counter.rs | 2 ++ src/ecs/mod.rs | 24 +++++++++++++++++++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec88645..5834d45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,6 +78,7 @@ dependencies = [ "bevy_time", "bevy_ui", "bevy_utils", + "bevy_winit", "crossbeam-queue", "futures", "hashbrown 0.15.2", diff --git a/Cargo.toml b/Cargo.toml index e4eb953..a02118e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/actuate-rs/actuate" [features] animation = ["ecs", "dep:bevy_math", "dep:bevy_time", "dep:tokio"] -ecs = ["dep:bevy_app", "dep:bevy_ecs", "dep:bevy_hierarchy", "dep:bevy_utils"] +ecs = ["std", "dep:bevy_app", "dep:bevy_ecs", "dep:bevy_hierarchy", "dep:bevy_utils", "dep:bevy_winit"] executor = ["std", "dep:tokio"] material = ["ecs", "picking", "dep:bevy_color", "dep:bevy_text", "dep:bevy_ui"] picking = ["dep:bevy_picking"] @@ -37,6 +37,7 @@ bevy_text = { version = "0.15.0", optional = true } bevy_time = { version = "0.15.0", optional = true } bevy_ui = { version = "0.15.0", optional = true } bevy_utils = { version = "0.15.0", optional = true } +bevy_winit = { version = "0.15.0", optional = true } crossbeam-queue = { version = "0.3.11", default-features = false, features = ["alloc"] } futures = "0.3.31" hashbrown = "0.15.2" diff --git a/examples/counter.rs b/examples/counter.rs index 7500786..4dc4966 100644 --- a/examples/counter.rs +++ b/examples/counter.rs @@ -2,6 +2,7 @@ use actuate::prelude::*; use bevy::prelude::*; +use bevy_winit::WinitSettings; // Counter composable. #[derive(Data)] @@ -44,6 +45,7 @@ fn setup(mut commands: Commands) { fn main() { App::new() .add_plugins((DefaultPlugins, ActuatePlugin)) + .insert_resource(WinitSettings::desktop_app()) .add_systems(Startup, setup) .run(); } diff --git a/src/ecs/mod.rs b/src/ecs/mod.rs index d7a4877..3266995 100644 --- a/src/ecs/mod.rs +++ b/src/ecs/mod.rs @@ -13,6 +13,7 @@ use bevy_ecs::{ world::{CommandQueue, World}, }; use bevy_utils::HashMap; +use bevy_winit::{EventLoopProxy, EventLoopProxyWrapper, WakeUp}; use core::fmt; use slotmap::{DefaultKey, SlotMap}; use std::{ @@ -20,6 +21,8 @@ use std::{ collections::BTreeSet, mem, ptr, rc::Rc, + sync::Arc, + task::{Context, Wake, Waker}, }; #[cfg(feature = "picking")] @@ -186,6 +189,16 @@ impl Compose for CompositionContent { } } +struct RuntimeWaker { + proxy: EventLoopProxy, +} + +impl Wake for RuntimeWaker { + fn wake(self: Arc) { + self.proxy.send_event(WakeUp).unwrap(); + } +} + fn compose(world: &mut World) { RUNTIME_CONTEXT.with(|runtime_cx| { let mut cell = runtime_cx.borrow_mut(); @@ -217,11 +230,20 @@ fn compose(world: &mut World) { rt.commands.borrow_mut().apply(world); drop(rt); + let proxy = (*world + .get_resource::>() + .unwrap()) + .clone(); let rt = &mut *world.non_send_resource_mut::(); let mut composers = rt.composers.borrow_mut(); for rt_composer in composers.values_mut() { + let waker = Waker::from(Arc::new(RuntimeWaker { + proxy: proxy.clone(), + })); + let mut cx = Context::from_waker(&waker); + // TODO handle composition error. - let _ = rt_composer.composer.try_compose(); + let _ = rt_composer.composer.poll_compose(&mut cx); } }