use std::{any::Any, sync::{Arc, Mutex, RwLock}, thread::yield_now}; use bevy::{ecs::{component::ComponentId, world::unsafe_world_cell::{UnsafeEntityCell, UnsafeWorldCell}}, prelude::*, reflect::{ReflectFromPtr, TypeData}, utils::{hashbrown::HashMap, tracing::field}, window::PrimaryWindow}; use serde::{Deserialize, Serialize}; use space_editor::{prelude::Selected, space_editor_ui::inspector::inspect}; use wasm_bindgen::JsCast; use web_sys::HtmlElement; use crate::{ui::inspector::wasm::notify_dom_changed, wasm::{StaticBuffer, WasmMessageBuffer}}; use super::utils::{show_reflect, ComponentProp, Element, InspectedEntity, ReflectChange, VComponent, VNode, VirtualDom}; pub struct InspectorPlugin; impl Plugin for InspectorPlugin { fn build(&self, app: &mut App) { app.init_resource::(); app.add_systems(Update, show_selected); app.world.resource_mut::().add_simple::(); app.world.resource_mut::().add_simple::(); } } #[derive(Resource, Default)] struct InspectorFunctions { get_reflects: Vec) -> Option> + Send + Sync>> } impl InspectorFunctions { fn add_getter) -> Option> + Send + Sync + 'static>(&mut self, f: F) { self.get_reflects.push(Box::new(f)); } fn add_simple(&mut self) where T: bevy::prelude::Component + Reflect + FromReflect + 'static { unsafe { self.add_getter( |cell| { if let Some(val) = cell.get::() { Some(Box::new(::from_reflect(val).unwrap()) as Box) } else { None } } ) } } fn get_reflect_copy(&mut self, cell: &UnsafeEntityCell<'_>) -> Vec> { self.get_reflects.iter_mut().map(|f| (*f)(cell)).flatten().collect() } } fn show_selected( world: &mut World ) { if !world.is_resource_added::() { world.init_resource::(); } unsafe { let cell = world.as_unsafe_world_cell(); let mut virtial_dom = cell.get_resource_mut::().unwrap(); let Some(selection) = cell.get_resource::() else { let muts = virtial_dom.render(None); let q_window = cell.world_mut().query_filtered::<&Window, With>().single(cell.world()); let _ = notify_dom_changed(q_window, serde_json::to_string(&muts).unwrap()); return; }; let selected_entity = selection.0; let mut functions = cell.get_resource_mut::().unwrap(); let app_type_registry = cell.get_resource::().unwrap(); let e = cell.get_entity(selected_entity).unwrap(); if let Some(changes) = super::utils::wasm::ONCHAGE_BUFFER.take_message() { for (id, value) in changes { info!("change: {} : {}", id, value); virtial_dom.on_change_events.execute(cell.world_mut(), id, value); } } let mut inspected = InspectedEntity::none(); inspected.id = Some(e.id()); inspected.components = functions.get_reflect_copy(&e); let id = e.id(); let components = cell.components(); let element = Element::Component(super::utils::Component { tag: "div".to_string(), attributes: vec![ ("style".to_string(), "display: flex; flex-direction: column; height: 100%; overflow: auto;".to_string()), ("class".to_string(), "inspector".to_string()) ], children: inspected.components.into_iter().map(|c| { show_reflect( c.as_ref(), ReflectChange { entity_id: id, reflect_path: "".to_string(), compoent_id: format!("{:?}", components.get_id(c.get_represented_type_info().unwrap().type_id()).unwrap()), } ) }) .filter_map(|v| v) .collect(), ..Default::default() }); let muts = virtial_dom.render(Some(element)); let q_window = cell.world_mut().query_filtered::<&Window, With>().single(cell.world()); let _ = notify_dom_changed(q_window, serde_json::to_string(&muts).unwrap()); } } #[cfg(feature = "wasm")] mod wasm { use bevy::{prelude::*, window::PrimaryWindow}; use serde_json::json; use wasm_bindgen::prelude::*; use crate::wasm::*; use super::*; #[wasm_bindgen(typescript_custom_section)] const EVENT_DECLARATION: &str = r#" /** * An event indicating that an entity has been selected or that the selection * has been cleared. */ export interface InspectorDomChanged extends CustomEvent { /** The selected entity ID. If `null`, the selection has been cleared. */ detail: string | null; } declare global { export interface HTMLElementEventMap { "inspector-dom-changed": InspectorDomChanged; } } "#; pub(super) fn notify_dom_changed( q_window: &Window, msg : String, ) -> Result<(), String> { wasm::dispatch_to_js(q_window, "inspector-dom-changed", &msg) } }