use bevy::prelude::*; use crate::scene::{SceneElement, SceneSpawnerSystem, SceneState}; pub struct ChangeTrackingPlugin; impl Plugin for ChangeTrackingPlugin { fn build(&self, app: &mut App) { app.add_event::(); // Add more of these systems for each component that we want to track app.add_systems(Update, send_change_events::); app.add_systems( OnEnter(SceneState::Active), track_scene_elements.after(SceneSpawnerSystem), ); #[cfg(feature = "wasm")] app.add_systems( Update, wasm::send_change_events::.map(bevy::utils::error), ); } } #[derive(Component, Debug)] pub struct ChangeTracker; fn send_change_events( query: Query, With)>, mut entity_change_writer: EventWriter, ) { for entity in query.iter() { entity_change_writer.send(EntityChangedEvent(entity)); } } fn track_scene_elements( mut cmd: Commands, q_scene_elements: Query, With, Without)>, ) { for element in q_scene_elements.iter() { cmd.entity(element).insert(ChangeTracker); } } #[derive(Event, Deref)] pub struct EntityChangedEvent(pub Entity); #[cfg(feature = "wasm")] mod wasm { use bevy::{prelude::*, window::PrimaryWindow}; use wasm_bindgen::prelude::wasm_bindgen; use crate::wasm; use super::ChangeTracker; #[wasm_bindgen(typescript_custom_section)] const ENTITY_CHANGES_EVENT: &str = r#" export interface EntityChangesEvent extends CustomEvent { type: "entity-changes"; detail: string[]; } declare global { export interface GlobalEventHandlersEventMap { "entity-changes": EntityChangesEvent; } } "#; pub(super) fn send_change_events( q_changed_ents: Query, With)>, q_window: Query<&Window, With>, ) -> Result<(), String> { if q_changed_ents.is_empty() { return Ok(()); } let Ok(window) = q_window.get_single() else { return Ok(()); }; let entities = q_changed_ents .iter() .map(|ent| format!("{ent:?}")) .collect::>(); wasm::dispatch_to_js(window, "entity-changes", &entities) } }