WIP: Direct world access for tick_dioxus_ui()

This commit is contained in:
JMS55 2023-12-15 16:20:05 -08:00
parent 98a22580a1
commit 138a2b5b20
2 changed files with 97 additions and 59 deletions

View file

@ -43,8 +43,6 @@ pub struct DioxusUiBundle {
#[derive(Component)] #[derive(Component)]
pub struct DioxusUiRoot { pub struct DioxusUiRoot {
virtual_dom: VirtualDomUnsafe, virtual_dom: VirtualDomUnsafe,
parent_to_children: HashMap<(Entity, u8), Entity>,
children_to_parent: EntityHashMap<Entity, Entity>,
element_id_to_bevy_ui_entity: HashMap<ElementId, Entity>, element_id_to_bevy_ui_entity: HashMap<ElementId, Entity>,
bevy_ui_entity_to_element_id: EntityHashMap<Entity, ElementId>, bevy_ui_entity_to_element_id: EntityHashMap<Entity, ElementId>,
templates: HashMap<String, BevyTemplate>, templates: HashMap<String, BevyTemplate>,
@ -55,8 +53,6 @@ impl DioxusUiRoot {
pub fn new(root_component: fn(Scope) -> Element) -> Self { pub fn new(root_component: fn(Scope) -> Element) -> Self {
Self { Self {
virtual_dom: VirtualDomUnsafe::new(root_component), virtual_dom: VirtualDomUnsafe::new(root_component),
parent_to_children: HashMap::new(),
children_to_parent: EntityHashMap::default(),
element_id_to_bevy_ui_entity: HashMap::new(), element_id_to_bevy_ui_entity: HashMap::new(),
bevy_ui_entity_to_element_id: EntityHashMap::default(), bevy_ui_entity_to_element_id: EntityHashMap::default(),
templates: HashMap::new(), templates: HashMap::new(),

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
apply_mutations::apply_mutations, apply_mutations::{apply_mutations, BevyTemplate},
deferred_system::DeferredSystemRegistry, deferred_system::DeferredSystemRegistry,
events::EventReaders, events::EventReaders,
hooks::{EcsContext, EcsSubscriptions}, hooks::{EcsContext, EcsSubscriptions},
@ -8,27 +8,27 @@ use crate::{
use bevy::{ use bevy::{
ecs::{ ecs::{
entity::Entity, entity::Entity,
system::{CommandQueue, Commands},
world::{Mut, World}, world::{Mut, World},
}, },
hierarchy::Parent,
prelude::{Deref, DerefMut}, prelude::{Deref, DerefMut},
utils::synccell::SyncCell, utils::{hashbrown::HashMap, synccell::SyncCell, EntityHashMap},
}; };
use dioxus::core::{Element, Scope, VirtualDom}; use dioxus::core::{Element, ElementId, Scope, VirtualDom};
use std::{mem, rc::Rc, sync::Arc}; use std::{any::Any, mem, rc::Rc, sync::Arc};
pub fn tick_dioxus_ui(world: &mut World) { pub fn tick_dioxus_ui(world: &mut World) {
run_deferred_systems(world);
let world_ptr: *mut World = world; let world_ptr: *mut World = world;
let world_cell = world.as_unsafe_world_cell(); let world_cell = world.as_unsafe_world_cell();
let ecs_subscriptions = unsafe { world_cell.get_resource::<EcsSubscriptions>().unwrap() };
let events = unsafe { let ui_events = unsafe {
world_cell world_cell
.get_resource_mut::<EventReaders>() .get_resource_mut::<EventReaders>()
.unwrap() .unwrap()
.get_dioxus_events(world_cell.get_resource().unwrap()) .get_dioxus_events(world_cell.get_resource().unwrap())
}; };
let mut command_queue = CommandQueue::default();
let mut commands = Commands::new_from_entities(&mut command_queue, world_cell.entities());
for (root_entity, mut dioxus_ui_root) in unsafe { for (root_entity, mut dioxus_ui_root) in unsafe {
world_cell world_cell
@ -38,8 +38,6 @@ pub fn tick_dioxus_ui(world: &mut World) {
} { } {
let DioxusUiRoot { let DioxusUiRoot {
virtual_dom, virtual_dom,
parent_to_children,
children_to_parent,
element_id_to_bevy_ui_entity, element_id_to_bevy_ui_entity,
bevy_ui_entity_to_element_id, bevy_ui_entity_to_element_id,
templates, templates,
@ -47,59 +45,33 @@ pub fn tick_dioxus_ui(world: &mut World) {
} = &mut *dioxus_ui_root; } = &mut *dioxus_ui_root;
let virtual_dom = virtual_dom.get(); let virtual_dom = virtual_dom.get();
let schedule_update = virtual_dom.base_scope().schedule_update_any(); dispatch_ui_events(
for scope_id in &*ecs_subscriptions.world_and_queries { &ui_events,
schedule_update(*scope_id); bevy_ui_entity_to_element_id,
} virtual_dom,
for (resource_id, scope_ids) in &*ecs_subscriptions.resources { unsafe { world_cell.world() },
if unsafe { world_cell.world() }.is_resource_changed_by_id(*resource_id) { );
for scope_id in scope_ids {
schedule_update(*scope_id);
}
}
}
virtual_dom schedule_ui_renders_from_ecs_subscriptions(
.base_scope() virtual_dom,
.provide_context(EcsContext { world: world_ptr }); unsafe { world_cell.get_resource::<EcsSubscriptions>().unwrap() },
unsafe { world_cell.world() },
);
for (mut target, name, data) in &events { render_ui(
let mut target_element_id = bevy_ui_entity_to_element_id.get(&target); virtual_dom,
while target_element_id.is_none() { needs_rebuild,
target = children_to_parent[&target];
target_element_id = bevy_ui_entity_to_element_id.get(&target);
}
virtual_dom.handle_event(name, Rc::clone(data), *target_element_id.unwrap(), true);
}
if *needs_rebuild {
apply_mutations(
virtual_dom.rebuild(),
parent_to_children,
children_to_parent,
element_id_to_bevy_ui_entity,
bevy_ui_entity_to_element_id,
templates,
root_entity,
&mut commands,
);
*needs_rebuild = false;
}
apply_mutations(
virtual_dom.render_immediate(),
parent_to_children,
children_to_parent,
element_id_to_bevy_ui_entity, element_id_to_bevy_ui_entity,
bevy_ui_entity_to_element_id, bevy_ui_entity_to_element_id,
templates, templates,
root_entity, root_entity,
&mut commands, unsafe { world_cell.world_mut() },
world_ptr,
); );
} }
}
command_queue.apply(world); fn run_deferred_systems(world: &mut World) {
for system_id in mem::take(&mut *world.resource_mut::<DeferredSystemRegistry>().run_queue) { for system_id in mem::take(&mut *world.resource_mut::<DeferredSystemRegistry>().run_queue) {
let _ = world.run_system(system_id); let _ = world.run_system(system_id);
} }
@ -115,6 +87,76 @@ pub fn tick_dioxus_ui(world: &mut World) {
}); });
} }
fn schedule_ui_renders_from_ecs_subscriptions(
virtual_dom: &mut VirtualDom,
ecs_subscriptions: &EcsSubscriptions,
world: &World,
) {
let schedule_update = virtual_dom.base_scope().schedule_update_any();
for scope_id in &*ecs_subscriptions.world_and_queries {
schedule_update(*scope_id);
}
for (resource_id, scope_ids) in &*ecs_subscriptions.resources {
if world.is_resource_changed_by_id(*resource_id) {
for scope_id in scope_ids {
schedule_update(*scope_id);
}
}
}
}
fn dispatch_ui_events(
events: &Vec<(Entity, &str, Rc<dyn Any>)>,
bevy_ui_entity_to_element_id: &mut EntityHashMap<Entity, ElementId>,
virtual_dom: &mut VirtualDom,
world: &World,
) {
for (mut target, name, data) in events {
let mut target_element_id = bevy_ui_entity_to_element_id.get(&target);
while target_element_id.is_none() {
target = world.entity(target).get::<Parent>().unwrap().get();
target_element_id = bevy_ui_entity_to_element_id.get(&target);
}
virtual_dom.handle_event(name, Rc::clone(data), *target_element_id.unwrap(), true);
}
}
fn render_ui(
virtual_dom: &mut VirtualDom,
needs_rebuild: &mut bool,
element_id_to_bevy_ui_entity: &mut HashMap<ElementId, Entity>,
bevy_ui_entity_to_element_id: &mut EntityHashMap<Entity, ElementId>,
templates: &mut HashMap<String, BevyTemplate>,
root_entity: Entity,
world: &mut World,
world_ptr: *mut World,
) {
virtual_dom
.base_scope()
.provide_context(EcsContext { world: world_ptr });
if *needs_rebuild {
apply_mutations(
virtual_dom.rebuild(),
element_id_to_bevy_ui_entity,
bevy_ui_entity_to_element_id,
templates,
root_entity,
world,
);
*needs_rebuild = false;
}
apply_mutations(
virtual_dom.render_immediate(),
element_id_to_bevy_ui_entity,
bevy_ui_entity_to_element_id,
templates,
root_entity,
world,
);
}
#[derive(Deref, DerefMut)] #[derive(Deref, DerefMut)]
pub struct VirtualDomUnsafe(pub SyncCell<VirtualDom>); pub struct VirtualDomUnsafe(pub SyncCell<VirtualDom>);
unsafe impl Send for VirtualDomUnsafe {} unsafe impl Send for VirtualDomUnsafe {}