make debug console top level

This commit is contained in:
Schrottkatze 2025-06-18 17:13:52 +02:00
parent d79475ae2a
commit 4c24f67cd5
Signed by: schrottkatze
SSH key fingerprint: SHA256:FPOYVeBy3QP20FEM42uWF1Wa/Qhlk+L3S2+Wuau/Auo
9 changed files with 111 additions and 68 deletions

81
src/debug.rs Normal file
View file

@ -0,0 +1,81 @@
//! Seperate out debugging uis/plugins in it's own module for cleanliness.
use bevy::prelude::*;
use bevy_inspector_egui::bevy_egui::EguiPlugin;
use clap::Subcommand;
use console::ConsoleLog;
use util::{console_err, console_log};
use crate::AppState;
mod console;
mod util {
use bevy::prelude::*;
use super::DebugEvent;
pub fn console_log(dbg_writer: &mut EventWriter<DebugEvent>, s: impl Into<String>) {
dbg_writer.write(DebugEvent::PrintToConsole {
error: false,
text: s.into(),
});
}
pub fn console_err(dbg_writer: &mut EventWriter<DebugEvent>, s: impl Into<String>) {
dbg_writer.write(DebugEvent::PrintToConsole {
error: false,
text: s.into(),
});
}
}
/// Debug system set.
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct DebugSet;
pub fn plugin(app: &mut App) {
app.add_plugins(EguiPlugin {
enable_multipass_for_primary_context: true,
})
.add_systems(Update, start_game.in_set(DebugSet))
.add_event::<DebugEvent>()
.add_plugins(console::plugin);
}
#[derive(Event, Debug, Subcommand, PartialEq, Eq)]
enum DebugEvent {
/// Close the debug console.
#[command(name = "close", aliases = ["close-console"])]
CloseDebugConsole,
/// Output a string to the console.
#[command(name = "echo", aliases = ["print", "print-to-console"])]
PrintToConsole {
/// Print as error
#[arg(short, long)]
error: bool,
/// The text to be printed in the console.
text: String,
},
/// Start the game
StartGame,
}
fn start_game(
mut dbg_reader: EventReader<DebugEvent>,
mut log: ResMut<ConsoleLog>,
cur_state: Res<State<AppState>>,
mut next_state: ResMut<NextState<AppState>>,
) {
for ev in dbg_reader.read() {
if *ev == DebugEvent::StartGame {
if *cur_state == AppState::Ingame {
log.err("Can't start game since it's already started.");
} else {
log.write("Starting game...");
next_state.set(AppState::Ingame);
}
}
}
}

View file

@ -1,12 +1,14 @@
use std::panic::Location;
use bevy::prelude::*; use bevy::prelude::*;
use ui::{ use ui::{
DebugConsole, autofocus, autoscroll, handle_open_console, process_prompt, update_content, DebugConsole, autofocus, autoscroll, handle_open_console, process_prompt, update_content,
update_scroll_position, update_scroll_position,
}; };
use crate::{AppState, cleanup::despawn, game::GameplaySet}; use crate::{AppState, cleanup::despawn};
use super::DebugEvent; use super::{DebugEvent, DebugSet};
mod cli; mod cli;
mod ui; mod ui;
@ -15,14 +17,12 @@ pub(super) fn plugin(app: &mut App) {
app.init_state::<ConsoleState>() app.init_state::<ConsoleState>()
.add_systems( .add_systems(
OnEnter(ConsoleState::Open), OnEnter(ConsoleState::Open),
(open_console, (autofocus, autoscroll).after(open_console)), (open_console, (autofocus, autoscroll).after(open_console)).in_set(DebugSet),
) )
.add_systems( .add_systems(
Update, Update,
( (
handle_open_console handle_open_console.run_if(in_state(ConsoleState::Closed)),
.in_set(GameplaySet)
.run_if(in_state(ConsoleState::Closed).and(in_state(AppState::Ingame))),
update_content.run_if(resource_changed::<ConsoleLog>), update_content.run_if(resource_changed::<ConsoleLog>),
( (
update_scroll_position, update_scroll_position,
@ -30,15 +30,19 @@ pub(super) fn plugin(app: &mut App) {
execute_console_events, execute_console_events,
) )
.run_if(in_state(ConsoleState::Open)), .run_if(in_state(ConsoleState::Open)),
), )
.in_set(DebugSet),
)
.add_systems(
OnExit(ConsoleState::Open),
despawn::<DebugConsole>.in_set(DebugSet),
) )
.add_systems(OnExit(ConsoleState::Open), despawn::<DebugConsole>)
.insert_resource::<ConsoleLog>(ConsoleLog::new()); .insert_resource::<ConsoleLog>(ConsoleLog::new());
} }
/// the usize is a read index /// the usize is a read index
#[derive(Resource, Clone)] #[derive(Resource, Clone)]
struct ConsoleLog(Vec<ConsoleEvent>, usize); pub struct ConsoleLog(Vec<ConsoleEvent>, usize);
impl ConsoleLog { impl ConsoleLog {
fn new() -> Self { fn new() -> Self {
@ -56,15 +60,15 @@ impl ConsoleLog {
res res
} }
pub fn input(&mut self, content: &str) { fn input(&mut self, content: &str) {
self.0.push(ConsoleEvent::Input(content.to_string())) self.0.push(ConsoleEvent::Input(content.to_string()))
} }
pub fn output(&mut self, content: &str) { pub fn write(&mut self, content: &str) {
self.0.push(ConsoleEvent::Output(content.to_string())) self.0.push(ConsoleEvent::Output(content.to_string()))
} }
pub fn error(&mut self, content: &str) { pub fn err(&mut self, content: &str) {
self.0.push(ConsoleEvent::Error(content.to_string())) self.0.push(ConsoleEvent::Error(content.to_string()))
} }
} }
@ -98,8 +102,9 @@ fn execute_console_events(
for ev in ev_reader.read() { for ev in ev_reader.read() {
match ev { match ev {
DebugEvent::CloseDebugConsole => next_state.set(ConsoleState::Closed), DebugEvent::CloseDebugConsole => next_state.set(ConsoleState::Closed),
DebugEvent::PrintToConsole { text } => log.output(text), DebugEvent::PrintToConsole { text, error: false } => log.write(text),
_ => todo!(), DebugEvent::PrintToConsole { text, error: true } => log.err(text),
_ => {}
}; };
} }
} }

View file

@ -1,20 +1,20 @@
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use crate::game::debug::DebugEvent; use crate::debug::DebugEvent;
pub(super) fn respond(line: &str) -> Result<DebugEvent, String> { pub(super) fn respond(line: &str) -> Result<DebugEvent, String> {
let args = shlex::split(line).ok_or("Invalid Quoting")?; let args = shlex::split(line).ok_or("Invalid Quoting")?;
let cli = Cli::try_parse_from(args).map_err(|e| e.to_string()); let cli = Cli::try_parse_from(args).map_err(|e| e.to_string());
// help detection // help detection
let command_contains_help = (line.contains("help") || line.contains("-h")); let command_contains_help = line.contains("help") || line.contains("-h");
let some_line_starts_with_usage = cli let some_line_starts_with_usage = cli
.as_ref() .as_ref()
.is_err_and(|item| item.lines().any(|line| line.starts_with("Usage: "))); .is_err_and(|item| item.lines().any(|line| line.starts_with("Usage: ")));
if command_contains_help && some_line_starts_with_usage { if command_contains_help && some_line_starts_with_usage {
let Err(text) = cli else { unreachable!() }; let Err(text) = cli else { unreachable!() };
return Ok(DebugEvent::PrintToConsole { text }); return Ok(DebugEvent::PrintToConsole { text, error: false });
} }
Ok(cli?.cmd) Ok(cli?.cmd)

View file

@ -16,7 +16,7 @@ use bevy_ui_text_input::TextSubmitEvent;
pub(super) use components::console; pub(super) use components::console;
use components::{Content, Prompt}; use components::{Content, Prompt};
use crate::game::debug::DebugEvent; use crate::debug::DebugEvent;
use super::{ConsoleEvent, ConsoleLog, ConsoleState, OPEN_CONSOLE_DEFAULT, cli::respond}; use super::{ConsoleEvent, ConsoleLog, ConsoleState, OPEN_CONSOLE_DEFAULT, cli::respond};
@ -75,7 +75,7 @@ pub fn process_prompt(
Ok(debug_ev) => { Ok(debug_ev) => {
debug_event_writer.write(debug_ev); debug_event_writer.write(debug_ev);
} }
Err(e) => log.error(&e), Err(e) => log.err(&e),
} }
} }
} }

View file

@ -1,7 +1,7 @@
use bevy::{ecs::spawn::SpawnWith, prelude::*}; use bevy::{ecs::spawn::SpawnWith, prelude::*};
use bevy_ui_text_input::{TextInputMode, TextInputNode, TextInputPrompt}; use bevy_ui_text_input::{TextInputMode, TextInputNode, TextInputPrompt};
use crate::game::debug::console::{ConsoleEvent, ConsoleLog}; use crate::debug::console::{ConsoleEvent, ConsoleLog};
use super::DebugConsole; use super::DebugConsole;

View file

@ -1,14 +0,0 @@
//! Seperate out debugging uis/plugins in it's own module for cleanliness.
use bevy::prelude::*;
use bevy_inspector_egui::bevy_egui::EguiPlugin;
pub fn plugin(app: &mut App) {
app.add_plugins(EguiPlugin {
enable_multipass_for_primary_context: true,
})
.add_plugins((
// WorldInspectorPlugin::new(),
// StateInspectorPlugin::<AppState>::new(),
// StateInspectorPlugin::<menus::CurrentMenu>::new(),
));
}

View file

@ -6,18 +6,7 @@ use crate::{
}; };
mod camera; mod camera;
mod debug;
mod scene; mod scene;
mod tram {
use bevy::prelude::*;
fn spawn_tram(
mut c: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
}
}
/// Gameplay system set. All functions in this control the gameplay (duh). /// Gameplay system set. All functions in this control the gameplay (duh).
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
@ -29,6 +18,6 @@ pub fn plugin(app: &mut App) {
OnExit(AppState::Ingame), OnExit(AppState::Ingame),
despawn::<cleanup::Scene>.in_set(GameplaySet), despawn::<cleanup::Scene>.in_set(GameplaySet),
) )
.add_plugins((debug::plugin, camera::plugin)); .add_plugins(camera::plugin);
app.configure_sets(Update, GameplaySet.run_if(in_state(AppState::Ingame))); app.configure_sets(Update, GameplaySet.run_if(in_state(AppState::Ingame)));
} }

View file

@ -1,19 +0,0 @@
use bevy::prelude::*;
use clap::Subcommand;
mod console;
#[derive(Event, Debug, Subcommand)]
enum DebugEvent {
/// Close the debug console.
#[command(name = "close", aliases = ["close-console"])]
CloseDebugConsole,
/// Output a string to the console.
#[command(name = "echo", aliases = ["print", "print-to-console"])]
PrintToConsole { text: String },
}
pub(super) fn plugin(app: &mut App) {
app.add_plugins(console::plugin).add_event::<DebugEvent>();
}

View file

@ -2,14 +2,15 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_skein::SkeinPlugin; use bevy_skein::SkeinPlugin;
use bevy_ui_text_input::TextInputPlugin; use bevy_ui_text_input::TextInputPlugin;
use clap::ValueEnum;
mod camera; mod camera;
mod cleanup; mod cleanup;
mod debugging; mod debug;
mod game; mod game;
mod menus; mod menus;
#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash, Reflect)] #[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash, Reflect, ValueEnum)]
#[allow(unused)] #[allow(unused)]
enum AppState { enum AppState {
#[default] #[default]
@ -23,7 +24,7 @@ fn main() {
.register_type::<TPCTarget>() .register_type::<TPCTarget>()
.add_systems(Startup, camera::setup) .add_systems(Startup, camera::setup)
.add_plugins((DefaultPlugins, TextInputPlugin)) .add_plugins((DefaultPlugins, TextInputPlugin))
.add_plugins((game::plugin, menus::plugin, debugging::plugin)) .add_plugins((game::plugin, menus::plugin, debug::plugin))
.add_plugins(SkeinPlugin::default()) .add_plugins(SkeinPlugin::default())
.init_state::<AppState>() .init_state::<AppState>()
.register_type::<AppState>() .register_type::<AppState>()