Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a quick plugin to inspect the render world's entities #171

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy-inspector-egui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
118 changes: 117 additions & 1 deletion crates/bevy-inspector-egui/src/quick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<M>(mut self, condition: impl Condition<M>) -> Self {
let condition_system = IntoSystem::into_system(condition);
self.condition = Mutex::new(Some(Box::new(condition_system) as BoxedCondition));
Expand Down Expand Up @@ -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<Option<BoxedCondition>>,
}

impl RenderWorldInspectorPlugin {
pub fn new() -> Self {
Self::default()
}

/// Only show the UI if the specified condition is active
pub fn run_if<M>(mut self, condition: impl Condition<M>) -> 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::<DefaultInspectorConfigPlugin>() {
app.add_plugins(DefaultInspectorConfigPlugin);
}
if !app.is_plugin_added::<EguiPlugin>() {
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::<ExtractedWindows>()
.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<Option<Res<Input<KeyCode>>>>,
extracted_inputs: Option<ResMut<Input<KeyCode>>>,
type_registry: Extract<Option<Res<AppTypeRegistry>>>,
extracted_type_registry: Option<ResMut<AppTypeRegistry>>,
) {
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());
}
}
}