diff --git a/crates/bevy-inspector-egui/Cargo.toml b/crates/bevy-inspector-egui/Cargo.toml index 6c9f225e..cfcb4bbd 100644 --- a/crates/bevy-inspector-egui/Cargo.toml +++ b/crates/bevy-inspector-egui/Cargo.toml @@ -26,6 +26,7 @@ bevy_asset = { version = "0.12" } bevy_core = { version = "0.12" } bevy_ecs = { version = "0.12" } bevy_hierarchy = { version = "0.12" } +bevy_input ={ version = "0.12" } bevy_log = { version = "0.12" } bevy_math = { version = "0.12" } bevy_reflect = { version = "0.12" } diff --git a/crates/bevy-inspector-egui/src/quick.rs b/crates/bevy-inspector-egui/src/quick.rs index c8c0e9fd..291cd07c 100644 --- a/crates/bevy-inspector-egui/src/quick.rs +++ b/crates/bevy-inspector-egui/src/quick.rs @@ -15,7 +15,9 @@ use bevy_ecs::{ prelude::*, query::ReadOnlyWorldQuery, schedule::BoxedCondition, system::ReadOnlySystem, }; use bevy_egui::{EguiContext, EguiPlugin}; +use bevy_input::{keyboard::KeyCode, Input}; use bevy_reflect::Reflect; +use bevy_render::{view::ExtractedWindows, Extract, ExtractSchedule, Render, RenderApp, RenderSet}; use bevy_window::PrimaryWindow; use pretty_type_name::pretty_type_name; @@ -50,7 +52,7 @@ impl WorldInspectorPlugin { Self::default() } - /// Only show the UI of the specified condition is active + /// Only show the UI if the specified condition is active pub fn run_if(mut self, condition: impl Condition) -> Self { let condition_system = IntoSystem::into_system(condition); self.condition = Mutex::new(Some(Box::new(condition_system) as BoxedCondition)); @@ -469,3 +471,117 @@ fn check_default_plugins(app: &bevy_app::App, name: &str) { ); } } + +/// Plugin displaying a egui window with a list of entities that exist +/// in the world of the [rendering sub-app](RenderApp) +/// +/// ```no_run +/// use bevy::prelude::*; +/// use bevy_inspector_egui::prelude::*; +/// use bevy_inspector_egui::quick::RenderWorldInspectorPlugin; +/// +/// fn main() { +/// App::new() +/// .add_plugins(DefaultPlugins) +/// .add_plugins(RenderWorldInspectorPlugin::new()) +/// .run(); +/// } +/// ``` +#[derive(Default)] +pub struct RenderWorldInspectorPlugin { + condition: Mutex>, +} + +impl RenderWorldInspectorPlugin { + pub fn new() -> Self { + Self::default() + } + + /// Only show the UI if the specified condition is active + pub fn run_if(mut self, condition: impl Condition) -> Self { + let condition_system = IntoSystem::into_system(condition); + self.condition = Mutex::new(Some(Box::new(condition_system) as BoxedCondition)); + self + } +} + +impl Plugin for RenderWorldInspectorPlugin { + fn build(&self, app: &mut bevy_app::App) { + check_default_plugins(app, "RenderWorldInspectorPlugin"); + + if !app.is_plugin_added::() { + app.add_plugins(DefaultInspectorConfigPlugin); + } + if !app.is_plugin_added::() { + app.add_plugins(EguiPlugin); + } + + let condition = self.condition.lock().unwrap().take(); + let mut system = render_world_inspector_ui.into_configs(); + if let Some(condition) = condition { + system.run_if_dyn(condition); + } + + if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { + render_app + .add_systems(ExtractSchedule, extract_resources) + .add_systems( + Render, + system + .in_set(RenderSet::Cleanup) + .before(World::clear_entities), + ); + } + } +} + +fn render_world_inspector_ui(world: &mut World) { + let Some(window_entity) = world + .get_resource::() + .and_then(|windows| windows.primary) + else { + return; + }; + let egui_context = world.query::<&mut EguiContext>().get(world, window_entity); + + let Ok(egui_context) = egui_context else { + return; + }; + let mut egui_context = egui_context.clone(); + + egui::Window::new("RenderWorld Inspector") + .default_size(DEFAULT_SIZE) + .show(egui_context.get_mut(), |ui| { + egui::ScrollArea::vertical().show(ui, |ui| { + bevy_inspector::ui_for_world_entities(world, ui); + ui.allocate_space(ui.available_size()); + }); + }); +} + +fn extract_resources( + mut commands: Commands, + inputs: Extract>>>, + extracted_inputs: Option>>, + type_registry: Extract>>, + extracted_type_registry: Option>, +) { + if let Some(inputs) = inputs.as_ref() { + if let Some(mut extracted_inputs) = extracted_inputs { + if inputs.is_changed() { + *extracted_inputs = inputs.as_ref().clone(); + } + } else { + commands.insert_resource(inputs.as_ref().clone()); + } + } + if let Some(type_registry) = type_registry.as_ref() { + if let Some(mut extracted_type_registry) = extracted_type_registry { + if type_registry.is_changed() { + *extracted_type_registry = type_registry.as_ref().clone(); + } + } else { + commands.insert_resource(type_registry.as_ref().clone()); + } + } +}