You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
martian-chess/src/debug.rs

272 lines
8.0 KiB
Rust

use bevy::window::WindowResized;
use crate::prelude::*;
pub(crate) struct DebugPlugin;
impl Plugin for DebugPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
FrameTimeDiagnosticsPlugin,
EntityCountDiagnosticsPlugin,
SystemInformationDiagnosticsPlugin,
))
.init_resource::<DebugInfo>()
.init_state::<DebugState>()
.add_systems(Update, (aabb_gizmo,))
// Systems that run in the editor mode
.add_systems(
Update,
(
selected_gizmo.run_if(any_with_component::<game::Selected>),
selected_position.run_if(any_with_component::<game::Selected>),
debug_piece.run_if(resource_changed::<display3d::PiecePointer>),
)
.run_if(in_state(DebugState::Enabled)),
)
.add_systems(Startup, init_debug_ui)
.add_systems(
Update,
(
toggle_debug_mode.run_if(on_event::<KeyboardInput>()),
display_diagnostics.run_if(in_state(DebugState::Enabled)),
toggle_debug_ui.run_if(state_changed::<DebugState>),
aspect_ratio.run_if(on_event::<WindowResized>()),
),
);
}
}
#[derive(Debug, Default, Resource)]
pub(crate) struct DebugInfo(HashMap<String, String>);
impl DebugInfo {
pub fn set(&mut self, key: String, val: String) -> Option<String> {
self.0.insert(key, val)
}
pub fn _get(&self, key: &String) -> Option<&String> {
self.0.get(key)
}
pub fn _clear(&mut self, key: String) {
self.0.remove(&key);
}
pub fn iter(&self) -> Iter<'_, String, String> {
self.0.iter()
}
}
/// Marker resource used to enable Debug mode when present
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
pub(crate) enum DebugState {
#[default]
Disabled,
Enabled,
}
#[derive(Debug, Component)]
struct DebugRoot;
#[derive(Debug, Component)]
struct DebugPiece;
fn toggle_debug_mode(
mut events: EventReader<KeyboardInput>,
current_state: Res<State<DebugState>>,
mut next_state: ResMut<NextState<DebugState>>,
) {
events
.read()
.filter(
|KeyboardInput {
state, key_code, ..
}| *state == ButtonState::Pressed && *key_code == KeyCode::F3,
)
.for_each(|_| match current_state.get() {
DebugState::Enabled => next_state.set(DebugState::Disabled),
DebugState::Disabled => next_state.set(DebugState::Enabled),
});
}
fn toggle_debug_ui(
mut visibility: Query<&mut Visibility, Or<(With<DebugRoot>, With<DebugPiece>)>>,
current_state: Res<State<DebugState>>,
) {
visibility.iter_mut().for_each(|mut vis| {
*vis = match current_state.get() {
DebugState::Enabled => Visibility::Visible,
DebugState::Disabled => Visibility::Hidden,
}
});
}
fn init_debug_ui(mut commands: Commands) {
commands
.spawn((
NodeBundle {
style: Style {
padding: UiRect::all(Val::Px(10.0)),
..default()
},
background_color: Color::BLACK.into(),
visibility: Visibility::Hidden,
..default()
},
DebugRoot,
))
.with_children(|parent| {
parent.spawn((
TextBundle {
style: Style { ..default() },
..default()
},
DebugRoot,
));
});
commands
.spawn((
NodeBundle {
style: Style {
padding: UiRect::all(Val::Px(10.0)),
position_type: PositionType::Absolute,
bottom: Val::Px(0.0),
right: Val::Px(0.0),
..default()
},
background_color: Color::BLACK.into(),
visibility: Visibility::Hidden,
..default()
},
DebugPiece,
))
.with_children(|parent| {
parent.spawn((
TextBundle {
style: Style { ..default() },
..default()
},
DebugPiece,
));
});
}
fn display_diagnostics(
mut root: Query<&mut Text, With<DebugRoot>>,
diagnostics: Res<DiagnosticsStore>,
debug_infos: Res<DebugInfo>,
) {
root.iter_mut().for_each(|mut text| {
text.sections = diagnostics
.iter()
.map(|d| {
format!(
"{}: {:.0}\n",
d.path().as_str(),
d.smoothed().unwrap_or(0.0),
)
})
.chain(debug_infos.iter().map(|(k, v)| format!("{}: {}\n", k, v)))
.map(|s| TextSection::new(s, TextStyle { ..default() }))
.collect();
text.sections.sort_unstable_by(|a, b| a.value.cmp(&b.value));
});
}
fn aabb_gizmo(
added: Query<Entity, Added<game::Selected>>,
mut removed: RemovedComponents<game::Selected>,
selected: Query<Entity, With<game::Selected>>,
current_state: Res<State<DebugState>>,
mut commands: Commands,
) {
added.iter().for_each(|e| {
commands.entity(e).insert(ShowAabbGizmo {
color: Some(Color::RED),
});
});
removed.read().for_each(|e| {
commands.entity(e).remove::<ShowAabbGizmo>();
});
match current_state.get() {
DebugState::Enabled => selected.iter().for_each(|e| {
commands.entity(e).insert(ShowAabbGizmo {
color: Some(Color::RED),
});
}),
DebugState::Disabled => selected.iter().for_each(|e| {
commands.entity(e).remove::<ShowAabbGizmo>();
}),
}
}
/// Draw a gizmo showing cardinal directions for a selected object
fn selected_gizmo(selected: Query<&GlobalTransform, With<game::Selected>>, mut gizmos: Gizmos) {
selected.iter().for_each(|g| {
let s = g.translation();
gizmos.ray(s, Vec3::X, Color::RED);
gizmos.ray(s, Vec3::Y, Color::GREEN);
gizmos.ray(s, Vec3::Z, Color::BLUE);
});
}
fn selected_position(
selected: Query<(Entity, &GlobalTransform), With<game::Selected>>,
mut debug_info: ResMut<debug::DebugInfo>,
) {
let val = selected
.iter()
.map(|(e, gt)| format!("\n{:?} {:?}", e, gt.translation()))
.collect::<Vec<String>>()
.join("");
debug_info.set("Position".into(), val);
}
fn debug_piece(
query: Query<
(
Entity,
Option<&Side>,
Option<&Piece>,
Option<&BoardIndex>,
Option<&display3d::Animating>,
Option<&Selected>,
),
With<BoardIndex>,
>,
pointer: Res<display3d::PiecePointer>,
mut root: Query<(&mut Text, &mut Visibility), With<DebugPiece>>,
// mut commands: Commands,
) {
// query.iter().nth(1).iter().for_each(|e| {
// commands.entity(*e).log_components();
// });
match *pointer {
display3d::PiecePointer(Some(e)) => {
if let Ok((e, si, p, bi, a, sel)) = query.get(e) {
root.iter_mut().for_each(|(mut text, mut vis)| {
let value = format!("Entity: {:?}\nSide: {:?}\nPiece: {:?}\nBoard Index: {:?}\nAnimating: {:?}\nSelected: {:?}", e, si, p, bi, a, sel);
*text = Text::from_section(value, TextStyle { ..default() });
*vis = Visibility::Inherited;
});
}
}
_ => {
root.iter_mut().for_each(|(_, mut vis)| {
*vis = Visibility::Hidden;
});
}
}
}
fn aspect_ratio(mut debug_info: ResMut<DebugInfo>, window: Query<&Window>) {
window.iter().for_each(|window| {
let x = window.resolution.width();
let y = window.resolution.height();
let aspect_ratio = format!("{}x{}", x, y);
debug_info.set("aspect Ratio".into(), aspect_ratio);
})
}