Added debug cylinder for selected entity. Added frame time graph.

This commit is contained in:
Ben Wallis 2021-05-09 14:55:08 +01:00
parent 483711ba67
commit 1c80ab705f
5 changed files with 243 additions and 80 deletions

View File

@ -33,6 +33,7 @@ pub mod combat;
pub mod comp;
#[cfg(not(target_arch = "wasm32"))]
pub mod consts;
pub mod debug_info;
#[cfg(not(target_arch = "wasm32"))] pub mod depot;
#[cfg(not(target_arch = "wasm32"))]
pub mod effect;
@ -77,7 +78,6 @@ pub mod uid;
#[cfg(not(target_arch = "wasm32"))] pub mod vol;
#[cfg(not(target_arch = "wasm32"))]
pub mod volumes;
pub mod debug_info;
#[cfg(not(target_arch = "wasm32"))]
pub use cached_spatial_grid::CachedSpatialGrid;

View File

@ -10,9 +10,14 @@ use common::{
comp,
comp::{Poise, PoiseState},
};
use core::mem;
#[cfg(feature = "use-dyn-lib")]
pub use dyn_lib::init;
use egui::{Color32, Grid, ScrollArea, Slider, Ui};
use egui::{
plot::{Plot, Value},
widgets::plot::Curve,
Color32, Grid, ScrollArea, Slider, Ui,
};
use std::{cmp::Ordering, ffi::CStr};
#[cfg(feature = "use-dyn-lib")]
@ -23,10 +28,17 @@ pub fn maintain(
egui_state: &mut EguiInnerState,
client: &Client,
debug_info: &Option<DebugInfo>,
) {
added_cylinder_shape_id: Option<u64>,
) -> EguiActions {
#[cfg(not(feature = "use-dyn-lib"))]
{
maintain_egui_inner(platform, egui_state, client, debug_info);
return maintain_egui_inner(
platform,
egui_state,
client,
debug_info,
added_cylinder_shape_id,
);
}
#[cfg(feature = "use-dyn-lib")]
@ -35,15 +47,14 @@ pub fn maintain(
let lib = &lock.as_ref().unwrap().lib;
let maintain_fn: libloading::Symbol<
fn(&mut Platform, &mut EguiInnerState, &Client, &Option<DebugInfo>),
> = unsafe {
//let start = std::time::Instant::now();
// Overhead of 0.5-5 us (could use hashmap to mitigate if this is an issue)
let f = lib.get(MAINTAIN_EGUI_FN);
//println!("{}", start.elapsed().as_nanos());
f
}
.unwrap_or_else(|e| {
fn(
&mut Platform,
&mut EguiInnerState,
&Client,
&Option<DebugInfo>,
Option<u64>,
) -> EguiActions,
> = unsafe { lib.get(MAINTAIN_EGUI_FN) }.unwrap_or_else(|e| {
panic!(
"Trying to use: {} but had error: {:?}",
CStr::from_bytes_with_nul(MAINTAIN_EGUI_FN)
@ -54,14 +65,66 @@ pub fn maintain(
)
});
maintain_fn(platform, egui_state, client, debug_info);
return maintain_fn(
platform,
egui_state,
client,
debug_info,
added_cylinder_shape_id,
);
}
}
pub struct SelectedEntityInfo {
entity_id: u32,
debug_shape_id: Option<u64>,
}
impl SelectedEntityInfo {
fn new(entity_id: u32) -> Self {
Self {
entity_id,
debug_shape_id: None,
}
}
}
pub struct EguiInnerState {
pub read_ecs: bool,
pub selected_entity_id: u32,
pub max_entity_distance: f32,
read_ecs: bool,
selected_entity_info: Option<SelectedEntityInfo>,
max_entity_distance: f32,
selected_entity_cylinder_height: f32,
frame_times: Vec<f32>,
}
impl EguiInnerState {
pub fn new() -> Self {
Self {
read_ecs: false,
selected_entity_info: None,
max_entity_distance: 100000.0,
selected_entity_cylinder_height: 10.0,
frame_times: Vec::new(),
}
}
}
pub enum DebugShapeAction {
AddCylinder {
radius: f32,
height: f32,
},
SetPosAndColor {
id: u64,
pos: [f32; 4],
color: [f32; 4],
},
RemoveCylinder(u64),
}
#[derive(Default)]
pub struct EguiActions {
pub actions: Vec<DebugShapeAction>,
}
#[cfg_attr(feature = "be-dyn-lib", export_name = "maintain_egui_inner")]
@ -70,27 +133,54 @@ pub fn maintain_egui_inner(
egui_state: &mut EguiInnerState,
client: &Client,
debug_info: &Option<DebugInfo>,
) {
added_cylinder_shape_id: Option<u64>,
) -> EguiActions {
platform.begin_frame();
let mut egui_actions = EguiActions::default();
let mut previous_selected_entity: Option<SelectedEntityInfo> = None;
let mut max_entity_distance = egui_state.max_entity_distance;
let mut selected_entity_cylinder_height = egui_state.selected_entity_cylinder_height;
// If a debug cylinder was added in the last frame, store it against the
// selected entity
if let Some(shape_id) = added_cylinder_shape_id {
if let Some(selected_entity) = &mut egui_state.selected_entity_info {
selected_entity.debug_shape_id = Some(shape_id);
}
}
debug_info.as_ref().map(|x| {
egui_state.frame_times.push(x.frame_time.as_nanos() as f32);
if egui_state.frame_times.len() > 250 {
egui_state.frame_times.remove(0);
}
});
if egui_state.read_ecs {
let ecs = client.state().ecs();
let positions = client.state().ecs().read_storage::<comp::Pos>();
let client_pos = positions.get(client.entity());
let mut max_entity_distance = egui_state.max_entity_distance;
egui::Window::new("ECS Entities")
.default_width(500.0)
.default_height(500.0)
.show(&platform.context(), |ui| {
ui.label(format!("Entity count: {}", &ecs.entities().join().count()));
ui.add(
Slider::new(&mut max_entity_distance, 1.0..=17000.0)
Slider::new(&mut max_entity_distance, 1.0..=100000.0)
.logarithmic(true)
.clamp_to_range(true)
.text("Max entity distance"),
);
ui.add(
Slider::new(&mut selected_entity_cylinder_height, 0.1..=100.0)
.logarithmic(true)
.clamp_to_range(true)
.text("Cylinder height"),
);
let mut scroll_area = ScrollArea::from_max_height(800.0);
let (current_scroll, max_scroll) = scroll_area.show(ui, |ui| {
// if scroll_top {
@ -108,16 +198,17 @@ pub fn maintain_egui_inner(
ui.label("Body");
ui.label("Poise");
ui.end_row();
for (entity, body, pos, ori, vel, poise) in (
for (entity, body, stats, pos, ori, vel, poise) in (
&ecs.entities(),
ecs.read_storage::<comp::Body>().maybe(),
ecs.read_storage::<comp::Stats>().maybe(),
ecs.read_storage::<comp::Pos>().maybe(),
ecs.read_storage::<comp::Ori>().maybe(),
ecs.read_storage::<comp::Vel>().maybe(),
ecs.read_storage::<comp::Poise>().maybe(),
)
.join()
.filter(|(_, _, pos, _, _, _)| {
.filter(|(_, _, _, pos, _, _, _)| {
client_pos.map_or(true, |client_pos| {
pos.map_or(0.0, |pos| pos.0.distance_squared(client_pos.0))
< max_entity_distance
@ -130,28 +221,40 @@ pub fn maintain_egui_inner(
// })
{
if ui.button("View").clicked() {
egui_state.selected_entity_id = entity.id();
previous_selected_entity =
mem::take(&mut egui_state.selected_entity_info);
if pos.is_some() {
egui_actions.actions.push(DebugShapeAction::AddCylinder {
radius: 1.0,
height: egui_state.selected_entity_cylinder_height,
});
}
egui_state.selected_entity_info =
Some(SelectedEntityInfo::new(entity.id()));
}
ui.label(format!("{}", entity.id()));
if let Some(pos) = pos {
ui.label(format!(
"{:.3},{:.3},{:.3}",
"{:.0},{:.0},{:.0}",
pos.0.x, pos.0.y, pos.0.z
));
} else {
ui.label("-");
}
if let Some(vel) = vel {
ui.label(format!(
"{:.3},{:.3},{:.3}",
"{:.1},{:.1},{:.1}",
vel.0.x, vel.0.y, vel.0.z
));
} else {
ui.label("-");
}
if let Some(body) = body {
ui.label(format!("{:?}", body));
if let Some(stats) = stats {
ui.label(&stats.name);
} else {
ui.label("-");
}
@ -174,42 +277,41 @@ pub fn maintain_egui_inner(
(current_scroll, max_scroll)
});
});
egui_state.max_entity_distance = max_entity_distance;
let selected_entity = ecs.entities().entity(egui_state.selected_entity_id);
if selected_entity.gen().is_alive() {
egui::Window::new("Selected Entity")
.default_width(300.0)
.default_height(200.0)
.show(&platform.context(), |ui| {
ui.horizontal_wrapped(|ui| {
for (entity, body, pos, ori, vel, poise, buffs) in (
&ecs.entities(),
ecs.read_storage::<comp::Body>().maybe(),
ecs.read_storage::<comp::Pos>().maybe(),
ecs.read_storage::<comp::Ori>().maybe(),
ecs.read_storage::<comp::Vel>().maybe(),
ecs.read_storage::<comp::Poise>().maybe(),
ecs.read_storage::<comp::Buffs>().maybe(),
)
.join()
.filter(|(e, _, _, _, _, _, _)| e.id() == egui_state.selected_entity_id)
{
if let Some(body) = body {
ui.group(|ui| {
ui.vertical(|ui| {
ui.label("Body");
Grid::new("selected_entity_body_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| {
ui.label("Type");
ui.label(format!("{:?}", body));
});
});
});
}
if let Some(selected_entity_info) = &mut egui_state.selected_entity_info {
let selected_entity = ecs.entities().entity(selected_entity_info.entity_id);
if !selected_entity.gen().is_alive() {
previous_selected_entity = mem::take(&mut egui_state.selected_entity_info);
} else {
for (entity, body, stats, pos, ori, vel, poise, buffs) in (
&ecs.entities(),
ecs.read_storage::<comp::Body>().maybe(),
ecs.read_storage::<comp::Stats>().maybe(),
ecs.read_storage::<comp::Pos>().maybe(),
ecs.read_storage::<comp::Ori>().maybe(),
ecs.read_storage::<comp::Vel>().maybe(),
ecs.read_storage::<comp::Poise>().maybe(),
ecs.read_storage::<comp::Buffs>().maybe(),
)
.join()
.filter(|(e, _, _, _, _, _, _, _)| e.id() == selected_entity_info.entity_id)
{
egui::Window::new(format!(
"Selected Entity - {}",
stats.as_ref().map_or("<No Name>", |x| &x.name)
))
.default_width(300.0)
.default_height(200.0)
.show(&platform.context(), |ui| {
ui.horizontal_wrapped(|ui| {
9-
if let Some(pos) = pos {
if let Some(shape_id) = selected_entity_info.debug_shape_id {
egui_actions.actions.push(DebugShapeAction::SetPosAndColor {
id: shape_id,
color: [1.0, 1.0, 0.0, 0.5],
pos: [pos.0.x, pos.0.y, pos.0.z + 2.0, 0.0],
});
}
ui.group(|ui| {
ui.vertical(|ui| {
ui.label("Pos");
@ -284,9 +386,10 @@ pub fn maintain_egui_inner(
});
});
}
}
});
});
});
}
}
}
}
@ -305,6 +408,46 @@ pub fn maintain_egui_inner(
egui_state.read_ecs = true;
}
});
egui::Window::new("Frame Time")
.default_width(200.0)
.default_height(200.0)
.show(&platform.context(), |ui| {
let plot = Plot::default().curve(Curve::from_values_iter(
egui_state
.frame_times
.iter()
.enumerate()
.map(|(i, x)| Value::new(i as f64, *x)),
));
ui.add(plot);
});
if let Some(previous) = previous_selected_entity {
if let Some(debug_shape_id) = previous.debug_shape_id {
egui_actions
.actions
.push(DebugShapeAction::RemoveCylinder(debug_shape_id));
}
};
if let Some(selected_entity) = &egui_state.selected_entity_info {
if let Some(debug_shape_id) = selected_entity.debug_shape_id {
if egui_state.selected_entity_cylinder_height != selected_entity_cylinder_height {
egui_actions
.actions
.push(DebugShapeAction::RemoveCylinder(debug_shape_id));
egui_actions.actions.push(DebugShapeAction::AddCylinder {
radius: 1.0,
height: selected_entity_cylinder_height,
});
}
}
};
egui_state.max_entity_distance = max_entity_distance;
egui_state.selected_entity_cylinder_height = selected_entity_cylinder_height;
egui_actions
}
fn poise_state_label(ui: &mut Ui, poise: &Poise) {

View File

@ -50,7 +50,7 @@ impl DebugShape {
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct DebugShapeId(u64);
pub struct DebugShapeId(pub u64);
pub struct Debug {
next_shape_id: DebugShapeId,

View File

@ -44,10 +44,10 @@ use crate::{
window::{AnalogGameInput, Event, GameInput},
Direction, Error, GlobalState, PlayState, PlayStateResult,
};
use common::debug_info::DebugInfo;
use egui_wgpu_backend::epi::App;
use hashbrown::HashMap;
use settings_change::Language::ChangeLanguage;
use common::debug_info::DebugInfo;
/// The action to perform after a tick
enum TickAction {
@ -1016,7 +1016,9 @@ impl PlayState for SessionState {
);
// Maintain egui (debug interface)
global_state.egui_state.maintain(&self.client.borrow(), &debug_info,);
global_state
.egui_state
.maintain(&self.client.borrow(), &mut self.scene, &debug_info);
// Look for changes in the localization files
if global_state.i18n.reloaded() {
@ -1457,10 +1459,7 @@ impl PlayState for SessionState {
drop(third_pass);
drawer.draw_egui(
&mut global_state.egui_state.platform,
scale_factor,
);
drawer.draw_egui(&mut global_state.egui_state.platform, scale_factor);
}
}

View File

@ -1,13 +1,18 @@
use crate::window::Window;
use crate::{
scene::{DebugShape, DebugShapeId, Scene},
window::Window,
};
use client::Client;
use common::debug_info::DebugInfo;
use core::mem;
use egui::FontDefinitions;
use egui_winit_platform::{Platform, PlatformDescriptor};
use voxygen_egui::EguiInnerState;
use voxygen_egui::{DebugShapeAction, EguiInnerState};
pub struct EguiState {
pub platform: Platform,
egui_inner_state: EguiInnerState,
new_debug_shape_id: Option<u64>,
}
impl EguiState {
@ -22,20 +27,36 @@ impl EguiState {
Self {
platform,
egui_inner_state: EguiInnerState {
read_ecs: false,
selected_entity_id: 0,
max_entity_distance: 17000.0,
},
egui_inner_state: EguiInnerState::new(),
new_debug_shape_id: None,
}
}
pub fn maintain(&mut self, client: &Client, debug_info: &Option<DebugInfo>) {
voxygen_egui::maintain(
pub fn maintain(&mut self, client: &Client, scene: &mut Scene, debug_info: &Option<DebugInfo>) {
let egui_actions = voxygen_egui::maintain(
&mut self.platform,
&mut self.egui_inner_state,
client,
debug_info,
mem::take(&mut self.new_debug_shape_id),
);
egui_actions.actions.iter().for_each(|action| match action {
DebugShapeAction::AddCylinder { height, radius } => {
let shape_id = scene.debug.add_shape(DebugShape::Cylinder {
height: *height,
radius: *radius,
});
self.new_debug_shape_id = Some(shape_id.0);
},
DebugShapeAction::RemoveCylinder(debug_shape_id) => {
scene.debug.remove_shape(DebugShapeId(*debug_shape_id));
},
DebugShapeAction::SetPosAndColor { id, pos, color } => {
scene
.debug
.set_pos_and_color(DebugShapeId(*id), pos.clone(), color.clone());
},
})
}
}