New system scheduler hook

This commit is contained in:
JMS55 2023-12-27 11:19:02 -08:00
parent 9776f179f9
commit cb57dca6b9
5 changed files with 44 additions and 78 deletions

View file

@ -48,13 +48,7 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseStateSend<Option<Entity>>) -
let mut entities = entities.into_iter().collect::<Vec<_>>();
entities.sort_by_key(|(entity, _)| *entity);
let spawn_entity = use_system(cx, {
let selected_entity = (*selected_entity).clone();
move |world: &mut World| {
let new_entity = world.spawn_empty();
selected_entity.write(Some(new_entity.id()));
}
});
let system_scheduler = use_system_scheduler(cx);
render! {
node {
@ -87,7 +81,13 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseStateSend<Option<Entity>>) -
}
Button {
onclick: move |event: Event<PointerButton>| if *event.data == PointerButton::Primary {
spawn_entity();
system_scheduler.schedule({
let selected_entity = (*selected_entity).clone();
move |world: &mut World| {
let new_entity = world.spawn_empty();
selected_entity.write(Some(new_entity.id()));
}
});
event.stop_propagation();
},
text { text: "Spawn Entity", text_size: "18" }

View file

@ -1,54 +1,36 @@
use bevy::{
ecs::{
system::{IntoSystem, Resource, SystemId},
world::World,
},
utils::HashMap,
};
use std::sync::Arc;
use crate::ecs_hooks::EcsContext;
use bevy::ecs::system::{IntoSystem, Resource, System};
use dioxus::core::ScopeState;
#[derive(Resource, Default)]
pub struct DeferredSystemRegistry {
// TODO: Replace ref_counts with Box<Vec<SystemId>> and insert SystemId into it on unmount
pub ref_counts: HashMap<SystemId, Arc<()>>,
pub run_queue: Box<Vec<SystemId>>,
pub struct DeferredSystemRunQueue {
pub run_queue: Box<Vec<Box<dyn System<In = (), Out = ()>>>>,
}
#[derive(Clone, Copy)]
struct DeferredSystem {
id: SystemId,
run_queue: *mut Vec<SystemId>,
pub struct DeferredSystemScheduler {
run_queue: *mut Vec<Box<dyn System<In = (), Out = ()>>>,
}
impl DeferredSystem {
fn schedule(&self) {
unsafe { &mut *self.run_queue }.push(self.id);
impl DeferredSystemScheduler {
pub fn schedule<S, M>(&self, system: S)
where
S: IntoSystem<(), (), M> + 'static,
M: 'static,
{
unsafe { &mut *self.run_queue }.push(Box::new(S::into_system(system)));
}
}
unsafe impl Send for DeferredSystem {}
unsafe impl Sync for DeferredSystem {}
unsafe impl Send for DeferredSystemScheduler {}
unsafe impl Sync for DeferredSystemScheduler {}
pub fn new_deferred_system<S, M>(
system: S,
world: &mut World,
) -> (impl Fn() + Send + Sync + Copy, Arc<()>)
where
S: IntoSystem<(), (), M> + 'static,
M: 'static,
{
let id = world.register_system(system);
let ref_count = Arc::new(());
let mut system_registry = world.resource_mut::<DeferredSystemRegistry>();
system_registry
.ref_counts
.insert(id, Arc::clone(&ref_count));
let deferred_system = DeferredSystem {
id,
run_queue: Box::as_mut(&mut system_registry.run_queue),
};
(move || deferred_system.schedule(), ref_count)
pub fn use_system_scheduler(cx: &ScopeState) -> DeferredSystemScheduler {
DeferredSystemScheduler {
run_queue: Box::as_mut(
&mut EcsContext::get_world(cx)
.resource_mut::<DeferredSystemRunQueue>()
.run_queue,
),
}
}

View file

@ -1,9 +1,9 @@
use crate::{deferred_system::new_deferred_system, UiContext};
use crate::UiContext;
use bevy::{
ecs::{
component::ComponentId,
query::{QueryState, ReadOnlyWorldQuery},
system::{IntoSystem, Query, Resource},
system::{Query, Resource},
world::{unsafe_world_cell::UnsafeWorldCell, World},
},
utils::{HashMap, HashSet},
@ -13,6 +13,8 @@ use dioxus::{
hooks::use_on_destroy,
};
pub use crate::deferred_system::use_system_scheduler;
#[derive(Default)]
pub(crate) struct EcsSubscriptions {
pub resources: Box<HashMap<ComponentId, HashSet<ScopeId>>>,
@ -25,7 +27,7 @@ pub(crate) struct EcsContext {
}
impl EcsContext {
fn get_world(cx: &ScopeState) -> &mut World {
pub fn get_world(cx: &ScopeState) -> &mut World {
unsafe {
&mut *cx
.consume_context::<EcsContext>()
@ -115,15 +117,6 @@ where
}
}
pub fn use_system<S, M>(cx: &ScopeState, system: S) -> impl Fn() + Send + Sync + Copy
where
S: IntoSystem<(), (), M> + 'static,
M: 'static,
{
cx.use_hook(|| new_deferred_system(system, EcsContext::get_world(cx)))
.0
}
pub struct DioxusUiQuery<'a, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> {
query_state: QueryState<Q, F>,
world_cell: UnsafeWorldCell<'a>,

View file

@ -13,7 +13,7 @@ mod use_state_send;
use self::{
apply_mutations::BevyTemplate,
deferred_system::DeferredSystemRegistry,
deferred_system::DeferredSystemRunQueue,
ecs_hooks::EcsSubscriptions,
events::{generate_mouse_enter_leave_events, EventReaders, MouseEnter, MouseExit},
tick::tick_dioxus_ui,
@ -47,7 +47,7 @@ impl Plugin for DioxusUiPlugin {
>::default());
app.init_non_send_resource::<UiContext>()
.init_resource::<DeferredSystemRegistry>()
.init_resource::<DeferredSystemRunQueue>()
.init_resource::<EventReaders>()
.add_event::<MouseEnter>()
.add_event::<MouseExit>()

View file

@ -1,6 +1,6 @@
use crate::{
apply_mutations::apply_mutations,
deferred_system::DeferredSystemRegistry,
deferred_system::DeferredSystemRunQueue,
ecs_hooks::EcsContext,
events::{bubble_event, EventReaders},
DioxusUiRoot, UiContext, UiRoot,
@ -12,7 +12,7 @@ use bevy::{
},
utils::HashMap,
};
use std::{any::Any, mem, rc::Rc, sync::Arc};
use std::{any::Any, mem, rc::Rc};
pub fn tick_dioxus_ui(world: &mut World) {
run_deferred_systems(world);
@ -55,19 +55,10 @@ pub fn tick_dioxus_ui(world: &mut World) {
}
fn run_deferred_systems(world: &mut World) {
for system_id in mem::take(&mut *world.resource_mut::<DeferredSystemRegistry>().run_queue) {
let _ = world.run_system(system_id);
for mut system in mem::take(&mut *world.resource_mut::<DeferredSystemRunQueue>().run_queue) {
system.initialize(world);
let _ = system.run((), world);
}
world.resource_scope(|world, mut system_registry: Mut<DeferredSystemRegistry>| {
system_registry.ref_counts.retain(|system_id, ref_count| {
let cleanup = Arc::strong_count(ref_count) == 1;
if cleanup {
world.remove_system(*system_id).unwrap();
}
!cleanup
});
});
}
fn dispatch_ui_events(