Added egui Inspection, Settings and Memory windows. Refactored selected entity window.

This commit is contained in:
Ben Wallis 2021-05-31 12:14:18 +01:00
parent 0296bbe696
commit 0b10752a7d
11 changed files with 457 additions and 158 deletions

View File

@ -13,7 +13,7 @@ pub use common_net::msg::ServerInfo;
pub use specs::{
join::Join,
saveload::{Marker, MarkerAllocator},
Builder, DispatcherBuilder, Entity as EcsEntity, ReadStorage, WorldExt,
Builder, DispatcherBuilder, Entity as EcsEntity, ReadStorage, World, WorldExt,
};
use crate::addr::ConnectionArgs;

View File

@ -85,7 +85,8 @@ impl Clock {
.map_or(self.last_dt.as_secs_f32(), |t| t.into_inner()),
);
if self.last_dts.len() >= NUMBER_OF_DELTAS_COMPARED && self.last_dt > 2 * stable_dt {
tracing::debug!(?self.last_dt, ?self.total_tick_time, "lag spike detected, unusually slow tick");
//tracing::debug!(?self.last_dt, ?self.total_tick_time, "lag spike detected,
// unusually slow tick");
stable_dt
} else {
self.last_dt

View File

@ -23,13 +23,14 @@ use crate::{
use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage};
use specs_idvs::IdvStorage;
use strum_macros::Display;
use vek::*;
use super::{BuffKind, Density, Mass};
make_case_elim!(
body,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, Display, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum Body {
Humanoid(body: humanoid::Body) = 0,

View File

@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage, VecStorage};
use specs_idvs::IdvStorage;
use std::collections::{BTreeMap, VecDeque};
use strum_macros::Display;
use vek::*;
/// Data returned from character behavior fn's to Character Behavior System.
@ -42,7 +43,7 @@ impl From<&JoinData<'_>> for StateUpdate {
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, Display, PartialEq, Serialize, Deserialize)]
pub enum CharacterState {
Idle,
Climb(climb::Data),

View File

@ -554,6 +554,7 @@ impl Item {
ability_map,
msm,
);
new_item.set_amount(self.amount()).expect(
"`new_item` has the same `item_def` and as an invariant, \
self.set_amount(self.amount()) should always succeed.",

View File

@ -15,6 +15,8 @@ use crate::{
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use strum_macros::Display;
use vek::*;
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
@ -782,7 +784,7 @@ pub fn tick_attack_or_default(
/// Determines what portion a state is in. Used in all attacks (eventually). Is
/// used to control aspects of animation code, as well as logic within the
/// character states.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, Display, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum StageSection {
Buildup,
Swing,

View File

@ -118,7 +118,7 @@ pub fn init(
package_source_dir: &'static str,
) {
let mut lock = lib_storage.lock().unwrap();
*lock = Some(LoadedLib::compile_load(package));
*lock = Some(LoadedLib::compile_load(dyn_package));
// TODO: use crossbeam
let (reload_send, reload_recv) = mpsc::channel();
@ -201,7 +201,7 @@ fn event_fn(res: notify::Result<notify::Event>, sender: &mpsc::Sender<String>) {
.for_each(|p| { let _ = sender.send(p); });
}
},
Err(e) => error!(?e, "egui hotreload watcher error."),
Err(e) => error!(?e, "hotreload watcher error."),
}
}
@ -222,11 +222,11 @@ fn hotreload(dyn_package: &str, loaded_lib: Arc<Mutex<Option<LoadedLib>>>) {
// Open new lib.
*lock = Some(LoadedLib::load(dyn_package));
info!("Updated egui.");
info!("Updated {}.", dyn_package);
}
}
/// Recompile the anim package
/// Recompile the dyn package
///
/// Returns `false` if the compile failed.
fn compile(dyn_package: &str) -> bool {
@ -234,8 +234,6 @@ fn compile(dyn_package: &str) -> bool {
.stderr(Stdio::inherit())
.stdout(Stdio::inherit())
.arg("build")
.arg("-v")
.arg("-v")
.arg("--package")
.arg(dyn_package)
.arg("--features")

View File

@ -0,0 +1,77 @@
use crate::{two_col_row, SelectedEntityInfo};
use common::{
comp::CharacterState,
states::{charged_melee, combo_melee, dash_melee, leap_melee},
};
use egui::{Grid, Ui};
pub fn draw_char_state_group(
ui: &mut Ui,
_selected_entity_info: &SelectedEntityInfo,
character_state: &CharacterState,
) {
ui.horizontal(|ui| {
ui.label("Current State: ");
ui.label(format!("{}", character_state.to_string()));
});
match character_state {
CharacterState::ComboMelee(data) => {
combo_melee_grid(ui, data);
},
CharacterState::DashMelee(data) => dash_melee_grid(ui, data),
CharacterState::ChargedMelee(data) => charged_melee_grid(ui, data),
CharacterState::LeapMelee(data) => leap_melee_grid(ui, data),
_ => {},
};
}
fn charged_melee_grid(ui: &mut Ui, data: &charged_melee::Data) {
Grid::new("selected_entity_charged_melee_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| #[rustfmt::skip] {
two_col_row(ui, "Stage Section", format!("{}", data.stage_section));
two_col_row(ui, "Timer", format!("{}ms", data.timer.as_millis()));
two_col_row(ui, "Charge Amount", format!("{:.1}", data.charge_amount));
two_col_row(ui, "Exhausted", format!("{}", if data.exhausted { "True" } else { "False " }));
});
}
fn combo_melee_grid(ui: &mut Ui, data: &combo_melee::Data) {
Grid::new("selected_entity_combo_melee_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| #[rustfmt::skip] {
two_col_row(ui, "Stage", format!("{}", data.stage));
two_col_row(ui, "Timer", format!("{}ms", data.timer.as_millis()));
two_col_row(ui, "num_stages", format!("{}", data.static_data.num_stages));
});
}
fn dash_melee_grid(ui: &mut Ui, data: &dash_melee::Data) {
Grid::new("selected_entity_dash_melee_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| #[rustfmt::skip] {
two_col_row(ui, "Auto Charge", format!("{}", if data.auto_charge { "True" } else { "False " }));
two_col_row(ui, "Timer", format!("{}ms", data.timer.as_millis()));
two_col_row(ui, "Stage Section", data.stage_section.to_string());
two_col_row(ui, "Exhausted", format!("{}", if data.exhausted { "True" } else { "False " }));
two_col_row(ui, "Charge End Timer", format!("{}ms", data.charge_end_timer.as_millis()));
});
}
fn leap_melee_grid(ui: &mut Ui, data: &leap_melee::Data) {
Grid::new("selected_entity_leap_melee_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| #[rustfmt::skip] {
two_col_row(ui, "Stage Section", format!("{}", data.stage_section));
two_col_row(ui, "Timer", format!("{}ms", data.timer.as_millis()));
two_col_row(ui, "Exhausted", format!("{}", if data.exhausted { "True" } else { "False " }));
});
}

View File

@ -1,6 +1,8 @@
#![feature(stmt_expr_attributes)]
mod character_states;
#[cfg(all(feature = "be-dyn-lib", feature = "use-dyn-lib"))]
compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once");
use client::{Client, Join, WorldExt};
use client::{Client, Join, World, WorldExt};
use common::{
comp,
comp::{Poise, PoiseState},
@ -10,8 +12,17 @@ use core::mem;
use egui::{
plot::{Plot, Value},
widgets::plot::Curve,
Color32, Grid, ScrollArea, Slider, Ui,
CollapsingHeader, Color32, Grid, Label, ScrollArea, Slider, Ui, Window,
};
fn two_col_row(ui: &mut Ui, label: impl Into<Label>, content: impl Into<Label>) {
ui.label(label);
ui.label(content);
ui.end_row();
}
use crate::character_states::draw_char_state_group;
use common::comp::{aura::AuraKind::Buff, Body, Fluid};
use egui_winit_platform::Platform;
#[cfg(feature = "use-dyn-lib")]
use lazy_static::lazy_static;
@ -88,6 +99,7 @@ pub fn maintain(
pub struct SelectedEntityInfo {
entity_id: u32,
debug_shape_id: Option<u64>,
character_state_history: Vec<String>,
}
impl SelectedEntityInfo {
@ -95,6 +107,7 @@ impl SelectedEntityInfo {
Self {
entity_id,
debug_shape_id: None,
character_state_history: Vec::new(),
}
}
}
@ -105,6 +118,9 @@ pub struct EguiInnerState {
max_entity_distance: f32,
selected_entity_cylinder_height: f32,
frame_times: Vec<f32>,
show_inspection_ui: bool,
show_settings_ui: bool,
show_memory_ui: bool,
}
impl Default for EguiInnerState {
@ -115,6 +131,9 @@ impl Default for EguiInnerState {
max_entity_distance: 100000.0,
selected_entity_cylinder_height: 10.0,
frame_times: Vec::new(),
show_inspection_ui: false,
show_settings_ui: false,
show_memory_ui: false,
}
}
}
@ -146,6 +165,8 @@ pub fn maintain_egui_inner(
added_cylinder_shape_id: Option<u64>,
) -> EguiActions {
platform.begin_frame();
let ctx = &platform.context();
let mut egui_actions = EguiActions::default();
let mut previous_selected_entity: Option<SelectedEntityInfo> = None;
let mut max_entity_distance = egui_state.max_entity_distance;
@ -168,6 +189,66 @@ pub fn maintain_egui_inner(
}
};
egui::Window::new("Test Window")
.default_width(200.0)
.default_height(200.0)
.show(&platform.context(), |ui| {
ui.heading("Debug UI");
ui.horizontal(|ui| {
ui.label(format!(
"Ping: {:.1}ms",
debug_info.as_ref().map_or(0.0, |x| x.ping_ms)
));
});
if ui.button("Enable ECS reading").clicked() {
egui_state.read_ecs = true;
}
ui.group(|ui| {
ui.vertical(|ui| {
ui.label("Show EGUI Windows");
ui.horizontal(|ui| {
ui.checkbox(&mut egui_state.show_inspection_ui, "🔍 Inspection");
ui.checkbox(&mut egui_state.show_settings_ui, "🔍 Settings");
ui.checkbox(&mut egui_state.show_memory_ui, "📝 Memory");
})
})
});
});
Window::new("🔧 Settings")
.open(&mut egui_state.show_settings_ui)
.scroll(true)
.show(ctx, |ui| {
ctx.settings_ui(ui);
});
Window::new("🔍 Inspection")
.open(&mut egui_state.show_inspection_ui)
.scroll(true)
.show(ctx, |ui| {
ctx.inspection_ui(ui);
});
Window::new("📝 Memory")
.open(&mut egui_state.show_memory_ui)
.resizable(false)
.show(ctx, |ui| {
ctx.memory_ui(ui);
});
Window::new("Frame Time")
.default_width(200.0)
.default_height(200.0)
.show(ctx, |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 egui_state.read_ecs {
let ecs = client.state().ecs();
@ -177,7 +258,7 @@ pub fn maintain_egui_inner(
egui::Window::new("ECS Entities")
.default_width(500.0)
.default_height(500.0)
.show(&platform.context(), |ui| {
.show(ctx, |ui| {
ui.label(format!("Entity count: {}", &ecs.entities().join().count()));
ui.add(
Slider::new(&mut max_entity_distance, 1.0..=100000.0)
@ -207,10 +288,12 @@ pub fn maintain_egui_inner(
ui.label("ID");
ui.label("Pos");
ui.label("Vel");
ui.label("Name");
ui.label("Body");
ui.label("Poise");
ui.label("Character State");
ui.end_row();
for (entity, _body, stats, pos, _ori, vel, poise) in (
for (entity, body, stats, pos, _ori, vel, poise, character_state) in (
&ecs.entities(),
ecs.read_storage::<comp::Body>().maybe(),
ecs.read_storage::<comp::Stats>().maybe(),
@ -218,9 +301,10 @@ pub fn maintain_egui_inner(
ecs.read_storage::<comp::Ori>().maybe(),
ecs.read_storage::<comp::Vel>().maybe(),
ecs.read_storage::<comp::Poise>().maybe(),
ecs.read_storage::<comp::CharacterState>().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
@ -258,10 +342,7 @@ pub fn maintain_egui_inner(
}
if let Some(vel) = vel {
ui.label(format!(
"{:.1},{:.1},{:.1}",
vel.0.x, vel.0.y, vel.0.z
));
ui.label(format!("{:.1}u/s", vel.0.magnitude()));
} else {
ui.label("-");
}
@ -270,6 +351,11 @@ pub fn maintain_egui_inner(
} else {
ui.label("-");
}
if let Some(body) = body {
ui.label(body_species(&body));
} else {
ui.label("-");
}
if let Some(poise) = poise {
poise_state_label(ui, poise);
@ -277,6 +363,12 @@ pub fn maintain_egui_inner(
ui.label("-");
}
if let Some(character_state) = character_state {
ui.label(character_state.to_string());
} else {
ui.label("-");
}
ui.end_row();
}
});
@ -291,149 +383,15 @@ pub fn maintain_egui_inner(
});
if let Some(selected_entity_info) = &mut egui_state.selected_entity_info {
let selected_entity = ecs.entities().entity(selected_entity_info.entity_id);
//let selected_entity_id = 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| {
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");
Grid::new("selected_entity_pos_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| {
ui.label("x");
ui.label(format!("{}", pos.0.x));
ui.end_row();
ui.label("y");
ui.label(format!("{}", pos.0.y));
ui.end_row();
ui.label("z");
ui.label(format!("{}", pos.0.z));
ui.end_row();
});
});
});
}
if let Some(poise) = poise {
ui.group(|ui| {
ui.vertical(|ui| {
ui.label("Poise");
Grid::new("selected_entity_poise_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| {
ui.label("State");
poise_state_label(ui, poise);
ui.end_row();
ui.label("Current");
ui.label(format!("{}", poise.current()));
ui.end_row();
ui.label("Maximum");
ui.label(format!("{}", poise.maximum()));
ui.end_row();
ui.label("Base Max");
ui.label(format!("{}", poise.base_max()));
ui.end_row();
});
});
});
}
if let Some(buffs) = buffs {
ui.group(|ui| {
ui.vertical(|ui| {
ui.label("Buffs");
Grid::new("selected_entity_buffs_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| {
ui.label("Kind");
ui.label("Time");
ui.label("Source");
ui.end_row();
buffs.buffs.iter().for_each(|(_, v)| {
ui.label(format!("{:?}", v.kind));
ui.label(
v.time.map_or("-".to_string(), |time| {
format!("{:?}", time)
}),
);
ui.label(format!("{:?}", v.source));
ui.end_row();
});
});
});
});
}
});
});
}
selected_entity_window(platform, ecs, selected_entity_info, &mut egui_actions);
}
}
}
egui::Window::new("Test Window")
.default_width(200.0)
.default_height(200.0)
.show(&platform.context(), |ui| {
ui.heading("Debug UI");
ui.horizontal(|ui| {
ui.label(format!(
"Ping: {:.1}ms",
debug_info.as_ref().map_or(0.0, |x| x.ping_ms)
));
});
if ui.button("Enable ECS reading").clicked() {
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
@ -463,6 +421,266 @@ pub fn maintain_egui_inner(
egui_actions
}
fn selected_entity_window(
platform: &mut Platform,
ecs: &World,
selected_entity_info: &mut SelectedEntityInfo,
egui_actions: &mut EguiActions,
) {
let entity_id = selected_entity_info.entity_id;
for (
_entity,
body,
stats,
pos,
_ori,
vel,
poise,
buffs,
auras,
character_state,
physics_state,
alignment,
scale,
mass,
(density, health, energy),
) 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(),
ecs.read_storage::<comp::Auras>().maybe(),
ecs.read_storage::<comp::CharacterState>().maybe(),
ecs.read_storage::<comp::PhysicsState>().maybe(),
ecs.read_storage::<comp::Alignment>().maybe(),
ecs.read_storage::<comp::Scale>().maybe(),
ecs.read_storage::<comp::Mass>().maybe(),
(
ecs.read_storage::<comp::Density>().maybe(),
ecs.read_storage::<comp::Health>().maybe(),
ecs.read_storage::<comp::Energy>().maybe(),
),
)
.join()
.filter(|(e, _, _, _, _, _, _, _, _, _, _, _, _, _, (_, _, _))| e.id() == entity_id)
{
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],
});
}
};
egui::Window::new("Selected Entity")
.default_width(300.0)
.default_height(200.0)
.show(&platform.context(), |ui| {
ui.vertical(|ui| {
// let n = 128;
// let curve = egui::plot::Curve::from_values_iter((0..=n).map(|i| {
// use std::f64::consts::TAU;
// let x = egui::remap(i as f64, 0.0..=(n as f64), -TAU..=TAU);
// egui::plot::Value::new(x, x.sin())
// }));
// egui::plot::Plot::default()
// .curve(curve)
// .height(32.0)
// .data_aspect(1.0);
CollapsingHeader::new("General").default_open(true).show(ui, |ui| {
Grid::new("selected_entity_general_grid")
.spacing([40.0, 4.0])
.striped(true)
.show(ui, |ui| {
two_col_row(ui, "Health", health.map_or("-".to_owned(), |x| format!("{:.1}/{:.1}", x.current(), x.maximum())));
two_col_row(ui, "Energy", energy.map_or("-".to_owned(), |x| format!("{:.1}/{:.1}", x.current(), x.maximum())));
two_col_row(ui, "Position", pos.map_or("-".to_owned(), |x| format!("({:.1},{:.1},{:.1})", x.0.x, x.0.y, x.0.z)));
two_col_row(ui, "Velocity", vel.map_or("-".to_owned(), |x| format!("({:.1},{:.1},{:.1}) ({:.1} u/s)", x.0.x, x.0.y, x.0.z, x.0.magnitude())));
two_col_row(ui, "Alignment", alignment.map_or("-".to_owned(), |x| format!("{:?}", x)));
two_col_row(ui, "Scale", scale.map_or("-".to_owned(), |x| format!("{:?}", x)));
two_col_row(ui, "Mass", mass.map_or("-".to_owned(), |x| format!("{:.1}", x.0)));
two_col_row(ui, "Density", density.map_or("-".to_owned(), |x| format!("{:.1}", x.0)));
});
});
if let Some(stats) = stats {
CollapsingHeader::new("Stats").default_open(true).show(ui, |ui| {
Grid::new("selected_entity_stats_grid")
.spacing([40.0, 4.0])
.striped(true)
.show(ui, |ui| {
two_col_row(ui, "Name", format!("{}", stats.name));
two_col_row(ui, "Damage Reduction", format!("{:.1}", stats.damage_reduction));
two_col_row(ui, "Max Health Modifier", format!("{:.1}", stats.max_health_modifier));
two_col_row(ui, "Move Speed Modifier", format!("{:.1}", stats.move_speed_modifier));
});
});
}
if let Some(body) = body {
CollapsingHeader::new("Body").default_open(false).show(ui, |ui| {
Grid::new("selected_entity_body_grid")
.spacing([40.0, 4.0])
.striped(true)
.show(ui, |ui| {
two_col_row(ui, "Type", format!("{}", body.to_string()));
two_col_row(ui, "Species", format!("{}", body_species(body)));
});
});
}
if let Some(pos) = pos {
CollapsingHeader::new("Pos").default_open(false).show(ui, |ui| {
Grid::new("selected_entity_pos_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| {
two_col_row(ui, "x", format!("{:.1}", pos.0.x));
two_col_row(ui, "y", format!("{:.1}", pos.0.y));
two_col_row(ui, "z", format!("{:.1}", pos.0.z));
});
});
}
if let Some(poise) = poise {
CollapsingHeader::new("Poise").default_open(false).show(ui, |ui| {
Grid::new("selected_entity_poise_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| #[rustfmt::skip] {
ui.label("State");
poise_state_label(ui, poise);
ui.end_row();
two_col_row(ui, "Current", format!("{}/{}", poise.current(), poise.maximum()));
two_col_row(ui, "Base Max", format!("{}", poise.base_max()));
});
});
}
if let Some(buffs) = buffs {
CollapsingHeader::new("Buffs").default_open(false).show(ui, |ui| {
Grid::new("selected_entity_buffs_grid")
.spacing([40.0, 4.0])
.max_col_width(100.0)
.striped(true)
.show(ui, |ui| {
ui.label("Kind");
ui.label("Time");
ui.label("Source");
ui.end_row();
buffs.buffs.iter().for_each(|(_, v)| {
ui.label(format!("{:?}", v.kind));
ui.label(
v.time.map_or("-".to_string(), |time| {
format!("{:?}", time)
}),
);
ui.label(format!("{:?}", v.source));
ui.end_row();
});
});
});
}
if let Some(auras) = auras {
CollapsingHeader::new("Auras").default_open(false).show(ui, |ui| {
Grid::new("selected_entity_auras_grid")
.spacing([40.0, 4.0])
.striped(true)
.show(ui, |ui| {
ui.label("Kind");
ui.label("Radius");
ui.label("Duration");
ui.label("Target");
ui.end_row();
auras.auras.iter().for_each(|(_, v)| {
ui.label(match v.aura_kind {
Buff { kind, .. } => format!("Buff - {:?}", kind)
});
ui.label(format!("{:1}", v.radius));
ui.label(v.duration.map_or("-".to_owned(), |x| format!("{:1}s", x.as_secs())));
ui.label(format!("{:?}", v.target));
ui.end_row();
});
});
});
}
if let Some(character_state) = character_state {
if selected_entity_info
.character_state_history
.first()
.unwrap_or(&"-".to_owned())
!= &character_state.to_string()
{
selected_entity_info
.character_state_history
.insert(0, character_state.to_string());
if selected_entity_info.character_state_history.len() > 50 {
selected_entity_info.character_state_history.pop();
}
}
CollapsingHeader::new("Character State").default_open(false).show(ui, |ui| {
draw_char_state_group(ui, selected_entity_info, character_state);
});
}
if let Some(physics_state) = physics_state {
CollapsingHeader::new("Physics State").default_open(false).show(ui, |ui| {
Grid::new("selected_entity_physics_state_grid")
.spacing([40.0, 4.0])
.striped(true)
.show(ui, |ui| {
two_col_row(ui, "On Ground", format!("{}", if physics_state.on_ground { "True" } else { "False " }));
two_col_row(ui, "On Ceiling", format!("{}", if physics_state.on_ceiling { "True" } else { "False " }));
two_col_row(ui, "On Wall", physics_state.on_wall.map_or("-".to_owned(), |x| format!("{:.1},{:.1},{:.1}", x.x, x.y, x.z )));
two_col_row(ui, "Touching Entities", format!("{}", physics_state.touch_entities.len()));
two_col_row(ui, "In Fluid", match physics_state.in_fluid {
Some(Fluid::Air { elevation, .. }) => format!("Air (Elevation: {:.1})", elevation),
Some(Fluid::Water { depth, .. }) => format!("Water (Depth: {:.1})", depth),
_ => "None".to_owned() });
});
});
}
});
});
}
}
fn body_species(body: &Body) -> String {
match body {
Body::Humanoid(body) => format!("{:?}", body.species),
Body::QuadrupedSmall(body) => format!("{:?}", body.species),
Body::QuadrupedMedium(body) => format!("{:?}", body.species),
Body::BirdMedium(body) => format!("{:?}", body.species),
Body::FishMedium(body) => format!("{:?}", body.species),
Body::Dragon(body) => format!("{:?}", body.species),
Body::BirdLarge(body) => format!("{:?}", body.species),
Body::FishSmall(body) => format!("{:?}", body.species),
Body::BipedLarge(body) => format!("{:?}", body.species),
Body::BipedSmall(body) => format!("{:?}", body.species),
Body::Object(body) => format!("{:?}", body),
Body::Golem(body) => format!("{:?}", body.species),
Body::Theropod(body) => format!("{:?}", body.species),
Body::QuadrupedLow(body) => format!("{:?}", body.species),
Body::Ship(body) => format!("{:?}", body),
}
}
fn poise_state_label(ui: &mut Ui, poise: &Poise) {
match poise.poise_state() {
PoiseState::Normal => {

View File

@ -19,7 +19,8 @@ use common::{
clock::Clock,
};
use std::panic;
#[cfg(feature = "hot-anim")] use std::sync::Arc;
#[cfg(any(feature = "hot-anim", feature = "hot-egui"))]
use std::sync::Arc;
use tracing::{error, info, warn};
use veloren_voxygen::ui::egui::EguiState;

View File

@ -11,7 +11,6 @@
arbitrary_enum_discriminant,
bool_to_option,
const_generics,
or_patterns,
const_panic,
label_break_value,
array_map