bevy-inspector-egui v0.15.0-pre.0 Announcement and Migration Guide
I just released the next version 0.15.0-pre.0 of bevy-inspector-egui and would like to gather some feedback before the actual release.
If you just want a stable release for bevy 0.9, feel free to continue using bevy-inspector-egui 0.14.
If you miss any features from the previous release, or have suggestions for features or API design, please open an issue at bevy-inspector-egui/issues or ping me on the bevy discord (in #project-collaboration @dubi steinkek#2182).
You can check out the 0.15.0 docs on docs.rs: https://docs.rs/bevy-inspector-egui/0.15.0-pre
What’s new in the update?
This release features the removal of the Inspectable trait in favor of reusing the existing Reflect trait. This leads to less derive boilerplate and more reusability, paving the way for non-egui Inspector implementations (in the general sense, could also be autocomplete in a console) and usage outside of bevy.
New APIs
The release is a rewrite from scratch so here’s the new layout of the crate. For more detail, you can browse the crate docs.
The main modules are:
egui_reflect_inspector - General-purpose machinery for displaying Reflect types using egui
bevy_inspector - Methods for displaying bevy resources, assets and entities
inspector_options - Way of associating options to fields using InspectorOptions
quick - Easy plugins for showing UI panels.
egui_reflect_inspector
This module has no knowledge of bevy and provides general purpose methods for displaying arbitrary &mut dyn Reflect or &dyn Reflect (that’s right, we support readonly UI now).
Most of the time however you can just use either the
quick module for an simple WorldInspectorPlugin/ResourceInspectorPlugin/StateInspectorPlugin plugins, or the
bevy_inspector module for functions like ui_for_resource, ui_for_entity, etc.
use bevy_reflect::{Reflect, TypeRegistry};
use bevy_inspector_egui::egui_reflect_inspector::{InspectorUi, Context};
#[derive(Reflect)]
struct Data {
value: f32,
}
fn ui(data: &mut Data, ui: &mut egui::Ui, type_registry: &TypeRegistry) -> bool {
let mut cx = Context::default();
let mut env = InspectorUi::new_no_short_circuit(type_registry, &mut cx);
env.ui_for_reflect(data, ui)
}
This is the minimum needed to display a value: the value, the Ui and the type registry. This is enough for basic usage, but consider a struct like this
pub struct StandardMaterial {
base_color: Color
base_color_texture: Option<Handle<Image>>
..
}
base_color can be reflected and displayed, but what about the Handle<Image>? To really display its value, you would need to access the Assets<Image> resource and look the handle up.
This is what the Context struct and the short_circuiting is about.
You can put a &mut World into the Context and InspectorUi::new(type_registry, cx, short_circuit, short_circuit_readonly) accepts to short circuiting methods, which will be asked at every step in the recursive reflect walking if you know a better way to display the struct.
We provide short circuiting methods capable of displaying Handles which look something like this:
fn short_circuit_handle(..) {
if value is Handle<?> {
let assets = context.world.resource::Assets<?asset_type>();
let value = assets.get_mut(handle);
return ui_for_reflect(value, ..);
}
return None;
}
As a user, you don’t have to worry about this, if you just use the InspectorUi::for_bevy constructor:
let world: &mut World = ..;
let standard_material: Handle<StandardMaterial> = ..;
let mut cx = Context {
world: Some(world.into()),
};
let mut env = InspectorUi::for_bevy(type_registry, &mut cx);
env.ui_for_reflect(value, ui)
This will just work and display the value of the StandardMaterial.
Side node about change detection
If you have a Mut value and directly write env.ui_for_reflect(&mut *value, ui) you will always trigger change detection.
The proper way to write this is
let changed = env.ui_for_reflect(value.bypass_change_detection(), ui);
if changed {
value.set_changed();
}
bevy_inspector
This module contains functions for quickly building UI for bevy apps.
The following example speaks for itself, for more info just look at the module docs.
use bevy_inspector_egui::bevy_inspector;
#[derive(Debug, Clone, Eq, PartialEq, Hash, Reflect)]
enum AppState { A, B, C }
fn show_ui(world: &mut World, ui: &mut egui::Ui) {
ui.heading("Msaa resource");
bevy_inspector::ui_for_resource::<Msaa>(world, ui);
ui.heading("App State");
bevy_inspector::ui_for_state::<AppState>(world, ui);
egui::CollapsingHeader::new("Entities")
.default_open(true)
.show(ui, |ui| {
bevy_inspector::ui_for_world_entities(world, ui);
});
egui::CollapsingHeader::new("Resources").show(ui, |ui| {
bevy_inspector::ui_for_resources(world, ui);
});
egui::CollapsingHeader::new("Assets").show(ui, |ui| {
bevy_inspector::ui_for_all_assets(world, ui);
});
}
quick
Plugins you can easily add to your app.
Pro: less typing
Con: less flexibility
#[derive(Reflect, Resource, Default, InspectorOptions)]
#[reflect(Resource, InspectorOptions)]
struct Configuration {
#[inspector(min = 0.0)]
value: f32,
}
#[derive(Reflect, Debug, Clone, Eq, PartialEq, Hash)]
enum AppState { A, B, C }
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(WorldInspectorPlugin)
.add_plugin(ResourceInspectorPlugin::<Configuration>::default())
.add_plugin(StateInspectorPlugin::<AppState>::default())
.add_state(AppState::A)
.init_resource::<Configuration>()
.register_type::<Configuration>()
.register_type::<AppState>()
.add_startup_system(setup)
.run();
}
If you want more control over the presentation (egui window vs side panel vs egui_dock), or over the content, you can just add an exclusive system like this:
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(DefaultInspectorConfigPlugin)
.add_plugin(EguiPlugin)
.add_system(ui)
.run();
}
fn ui(world: &mut World) {
let egui_context = world
.resource_mut::<bevy_egui::EguiContext>()
.ctx_mut()
.clone();
egui::Window::new("UI").show(&egui_context, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
bevy_inspector_egui::bevy_inspector::ui_for_world(world, ui);
ui.allocate_space(ui.available_size());
});
});
}
Migration Guide
WorldInspectorPlugin
Before
use bevy_inspector_egui::WorldInspectorPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(WorldInspectorPlugin)
.run();
}
After
use bevy_inspector_egui::quick::WorldInspectorPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(WorldInspectorPlugin)
.run();
}
Basic usage of the world inspector doesn’t actually change. The only difference is that registration works differently now and WorldInspectorParams is gone. If you want to have more customization, copy the implementation, it’s ~10 lines.
InspectorPlugin
To display a single resource, the InspectorPlugin has been replaced with the ResourceInspectorPlugin:
Before
#[derive(Resource, Inspectable, Default)]
struct Data {
the: f32,
values: String,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(InspectorPlugin::<Data>::new())
.run();
}
After
#[derive(Reflect, Resource, Default)]
#[reflect(Resource)]
struct Data {
the: f32,
values: String,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(ResourceInspectorPlugin::<Data>::new())
.init_type::<Default>()
.register_type::<Data>()
.run();
}
#[inspectable] Attributes
Before
The Reflect trait is not capable of reading and storing arbitrary attributes. Instead, you can add the InspectorOptions derive which will parse and typecheck the attributes, and insert a type-erased options struct into the type registry.
#[derive(Resource, Inspectable)]
struct Data {
#[inspectable(min = 10.0, max = 70.0)]
font_size: f32,
}
After
#[derive(Reflect, Resource, InspectorOptions)]
#[reflect(Resource, InspectorOptions)]
struct Data {
#[inspector(min = 10.0, max = 70.0)]
font_size: f32,
}
...
app.register_type::<Data>()
As I said in the beginning, if you have any feedback please open an issue or ping me on discord :)
bevy-inspector-egui
v0.15.0-pre.0Announcement and Migration GuideI just released the next version
0.15.0-pre.0ofbevy-inspector-eguiand would like to gather some feedback before the actual release.If you just want a stable release for bevy
0.9, feel free to continue usingbevy-inspector-egui0.14.If you miss any features from the previous release, or have suggestions for features or API design, please open an issue at bevy-inspector-egui/issues or ping me on the bevy discord (in
#project-collaboration@dubi steinkek#2182).You can check out the
0.15.0docs ondocs.rs: https://docs.rs/bevy-inspector-egui/0.15.0-preWhat’s new in the update?
This release features the removal of the
Inspectabletrait in favor of reusing the existingReflecttrait. This leads to less derive boilerplate and more reusability, paving the way for non-egui Inspector implementations (in the general sense, could also be autocomplete in a console) and usage outside of bevy.New APIs
The release is a rewrite from scratch so here’s the new layout of the crate. For more detail, you can browse the crate docs.
The main modules are:
egui_reflect_inspector- General-purpose machinery for displaying Reflect types using eguibevy_inspector- Methods for displaying bevy resources, assets and entitiesinspector_options- Way of associating options to fields using InspectorOptionsquick- Easy plugins for showing UI panels.egui_reflect_inspectorThis module has no knowledge of bevy and provides general purpose methods for displaying arbitrary
&mut dyn Reflector&dyn Reflect(that’s right, we support readonly UI now).Most of the time however you can just use either the
quickmodule for an simpleWorldInspectorPlugin/ResourceInspectorPlugin/StateInspectorPluginplugins, or thebevy_inspectormodule for functions likeui_for_resource,ui_for_entity, etc.This is the minimum needed to display a value: the value, the
Uiand the type registry. This is enough for basic usage, but consider a struct like thisbase_colorcan be reflected and displayed, but what about theHandle<Image>? To really display its value, you would need to access theAssets<Image>resource and look the handle up.This is what the
Contextstruct and theshort_circuiting is about.You can put a
&mut Worldinto the Context andInspectorUi::new(type_registry, cx, short_circuit, short_circuit_readonly)accepts to short circuiting methods, which will be asked at every step in the recursive reflect walking if you know a better way to display the struct.We provide short circuiting methods capable of displaying
Handles which look something like this:As a user, you don’t have to worry about this, if you just use the
InspectorUi::for_bevyconstructor:This will just work and display the value of the
StandardMaterial.Side node about change detection
If you have a
Mutvalue and directly writeenv.ui_for_reflect(&mut *value, ui)you will always trigger change detection.The proper way to write this is
bevy_inspectorThis module contains functions for quickly building UI for bevy apps.
The following example speaks for itself, for more info just look at the module docs.
quickPlugins you can easily add to your app.
Pro: less typing
Con: less flexibility
If you want more control over the presentation (egui window vs side panel vs
egui_dock), or over the content, you can just add an exclusive system like this:Migration Guide
WorldInspectorPluginBefore
After
Basic usage of the world inspector doesn’t actually change. The only difference is that registration works differently now and
WorldInspectorParamsis gone. If you want to have more customization, copy the implementation, it’s ~10 lines.InspectorPluginTo display a single resource, the
InspectorPluginhas been replaced with theResourceInspectorPlugin:Before
After
#[inspectable]AttributesBefore
The
Reflecttrait is not capable of reading and storing arbitrary attributes. Instead, you can add theInspectorOptionsderive which will parse and typecheck the attributes, and insert a type-erased options struct into the type registry.After
As I said in the beginning, if you have any feedback please open an issue or ping me on discord :)