diff --git a/cart-test/manifest.json b/cart-test/manifest.json index f0ed64d3..888d4658 100644 --- a/cart-test/manifest.json +++ b/cart-test/manifest.json @@ -4,6 +4,6 @@ "app_id": 1234, "title": "Cart de Teste", "app_version": "1.0.0", - "app_mode": "Invalid", + "app_mode": "Game", "entrypoint": "0" } diff --git a/crates/host-desktop/src/main.rs b/crates/host-desktop/src/main.rs index f087e620..85861849 100644 --- a/crates/host-desktop/src/main.rs +++ b/crates/host-desktop/src/main.rs @@ -5,6 +5,7 @@ mod log_sink; use crate::prometeu_runner::PrometeuRunner; use winit::event_loop::EventLoop; +use prometeu_core::firmware::BootTarget; use prometeu_core::telemetry::CertificationConfig; fn load_cap_config(path: &str) -> Option { @@ -37,14 +38,26 @@ fn main() -> Result<(), Box> { let args: Vec = std::env::args().collect(); let mut fs_root = None; let mut cap_config = None; - let mut cartridge_path = None; + let mut boot_target = BootTarget::Hub; let mut i = 1; // Pula o nome do executável while i < args.len() { match args[i].as_str() { - "run" => { + "--run" => { if i + 1 < args.len() { - cartridge_path = Some(args[i + 1].clone()); + boot_target = BootTarget::Cartridge { + path: args[i + 1].clone(), + debug: false, + }; + i += 1; + } + } + "--debug" => { + if i + 1 < args.len() { + boot_target = BootTarget::Cartridge { + path: args[i + 1].clone(), + debug: true, + }; i += 1; } } @@ -68,16 +81,7 @@ fn main() -> Result<(), Box> { let event_loop = EventLoop::new()?; let mut runner = PrometeuRunner::new(fs_root, cap_config); - - if let Some(path) = cartridge_path { - match runner.load_cartridge(&path) { - Ok(_) => println!("Cartridge loaded: {}", path), - Err(e) => { - eprintln!("Failed to load cartridge: {:?}", e); - return Ok(()); - } - } - } + runner.set_boot_target(boot_target); event_loop.run_app(&mut runner)?; diff --git a/crates/host-desktop/src/prometeu_runner.rs b/crates/host-desktop/src/prometeu_runner.rs index 566c7f74..c5573af6 100644 --- a/crates/host-desktop/src/prometeu_runner.rs +++ b/crates/host-desktop/src/prometeu_runner.rs @@ -3,7 +3,7 @@ use crate::fs_desktop_backend::HostDirBackend; use crate::log_sink::HostConsoleSink; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use pixels::{Pixels, SurfaceTexture}; -use prometeu_core::firmware::Firmware; +use prometeu_core::firmware::{BootTarget, Firmware}; use prometeu_core::hardware::{AudioCommand, InputSignals, OUTPUT_SAMPLE_RATE}; use prometeu_core::Hardware; use ringbuf::traits::{Consumer, Producer, Split}; @@ -42,6 +42,8 @@ pub struct PrometeuRunner { overlay_enabled: bool, + debug_waiting_for_start: bool, + audio_load_accum_us: u64, audio_load_samples: u64, audio_perf_consumer: Option>>>, @@ -51,6 +53,15 @@ pub struct PrometeuRunner { } impl PrometeuRunner { + pub(crate) fn set_boot_target(&mut self, boot_target: BootTarget) { + self.firmware.boot_target = boot_target.clone(); + if let BootTarget::Cartridge { debug: true, .. } = boot_target { + self.debug_waiting_for_start = true; + println!("[Debugger] Waiting for start command..."); + println!("[Debugger] (Stub: press D to start execution)"); + } + } + pub(crate) fn load_cartridge(&mut self, path: &str) -> Result<(), CartridgeError> { let cartridge = CartridgeLoader::load(path)?; self.firmware.load_cartridge(cartridge); @@ -82,6 +93,7 @@ impl PrometeuRunner { frames_since_last_update: 0, current_fps: 0.0, overlay_enabled: false, + debug_waiting_for_start: false, audio_load_accum_us: 0, audio_load_samples: 0, audio_perf_consumer: None, @@ -225,6 +237,12 @@ impl ApplicationHandler for PrometeuRunner { WindowEvent::KeyboardInput { event, .. } => { if let PhysicalKey::Code(code) = event.physical_key { let is_down = event.state == ElementState::Pressed; + + if is_down && code == KeyCode::KeyD && self.debug_waiting_for_start { + self.debug_waiting_for_start = false; + println!("[Debugger] Execution started!"); + } + match code { KeyCode::ArrowUp => self.input_signals.up_signal = is_down, KeyCode::ArrowDown => self.input_signals.down_signal = is_down, @@ -301,7 +319,9 @@ impl ApplicationHandler for PrometeuRunner { // 🔥 O coração do determinismo: consome o tempo em fatias exatas de 60Hz while self.accumulator >= self.frame_target_dt { - self.firmware.step_frame(&self.input_signals, &mut self.hardware); + if !self.debug_waiting_for_start { + self.firmware.step_frame(&self.input_signals, &mut self.hardware); + } // Envia comandos de áudio gerados neste frame para a thread de áudio if let Some(producer) = &mut self.audio_producer { diff --git a/crates/prometeu-core/src/firmware/boot_target.rs b/crates/prometeu-core/src/firmware/boot_target.rs new file mode 100644 index 00000000..ef215d2f --- /dev/null +++ b/crates/prometeu-core/src/firmware/boot_target.rs @@ -0,0 +1,11 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BootTarget { + Hub, + Cartridge { path: String, debug: bool }, +} + +impl Default for BootTarget { + fn default() -> Self { + Self::Hub + } +} diff --git a/crates/prometeu-core/src/firmware/firmware.rs b/crates/prometeu-core/src/firmware/firmware.rs index 323dc559..c9d628b2 100644 --- a/crates/prometeu-core/src/firmware/firmware.rs +++ b/crates/prometeu-core/src/firmware/firmware.rs @@ -1,3 +1,4 @@ +use crate::firmware::boot_target::BootTarget; use crate::firmware::firmware_state::{FirmwareState, LoadCartridgeStep, ResetStep}; use crate::firmware::prometeu_context::PrometeuContext; use crate::hardware::{HardwareBridge, InputSignals}; @@ -13,6 +14,7 @@ pub struct Firmware { pub os: PrometeuOS, pub hub: PrometeuHub, pub state: FirmwareState, + pub boot_target: BootTarget, state_initialized: bool, } @@ -23,6 +25,7 @@ impl Firmware { os: PrometeuOS::new(cap_config), hub: PrometeuHub::new(), state: FirmwareState::Reset(ResetStep), + boot_target: BootTarget::Hub, state_initialized: false, } } @@ -41,7 +44,7 @@ impl Firmware { self.change_state(next_state, signals, hw); } } - + pub fn change_state(&mut self, new_state: FirmwareState, signals: &InputSignals, hw: &mut dyn HardwareBridge) { self.on_exit(signals, hw); self.state = new_state; @@ -57,6 +60,7 @@ impl Firmware { vm: &mut self.vm, os: &mut self.os, hub: &mut self.hub, + boot_target: &self.boot_target, signals, hw, }; @@ -76,6 +80,7 @@ impl Firmware { vm: &mut self.vm, os: &mut self.os, hub: &mut self.hub, + boot_target: &self.boot_target, signals, hw, }; @@ -95,6 +100,7 @@ impl Firmware { vm: &mut self.vm, os: &mut self.os, hub: &mut self.hub, + boot_target: &self.boot_target, signals, hw, }; diff --git a/crates/prometeu-core/src/firmware/firmware_step_launch_hub.rs b/crates/prometeu-core/src/firmware/firmware_step_launch_hub.rs index 2663e65b..7b920d83 100644 --- a/crates/prometeu-core/src/firmware/firmware_step_launch_hub.rs +++ b/crates/prometeu-core/src/firmware/firmware_step_launch_hub.rs @@ -1,5 +1,7 @@ -use crate::firmware::firmware_state::{FirmwareState, HubHomeStep}; +use crate::firmware::boot_target::BootTarget; +use crate::firmware::firmware_state::{FirmwareState, HubHomeStep, LoadCartridgeStep}; use crate::firmware::prometeu_context::PrometeuContext; +use crate::model::CartridgeLoader; use crate::log::{LogLevel, LogSource}; #[derive(Debug, Clone)] @@ -11,7 +13,19 @@ impl LaunchHubStep { ctx.hub.init(); } - pub fn on_update(&mut self, _ctx: &mut PrometeuContext) -> Option { + pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option { + if let BootTarget::Cartridge { path, debug } = ctx.boot_target { + match CartridgeLoader::load(path) { + Ok(cartridge) => { + // No caso de debug, aqui poderíamos pausar, mas o requisito diz + // para o Runtime abrir o socket e aguardar. + return Some(FirmwareState::LoadCartridge(LoadCartridgeStep { cartridge })); + } + Err(e) => { + ctx.os.log(LogLevel::Error, LogSource::Pos, 0, format!("Failed to auto-load cartridge: {:?}", e)); + } + } + } Some(FirmwareState::HubHome(HubHomeStep)) } diff --git a/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs b/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs index e7863c1e..592ff4b8 100644 --- a/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs +++ b/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs @@ -22,6 +22,9 @@ impl LoadCartridgeStep { Color::WHITE ); ctx.hub.window_manager.set_focus(id); + + // Apps de sistema não mudam o estado do firmware para GameRunning. + // Eles rodam em background ou via janelas no Hub. return Some(FirmwareState::HubHome(HubHomeStep)); } diff --git a/crates/prometeu-core/src/firmware/firmware_step_reset.rs b/crates/prometeu-core/src/firmware/firmware_step_reset.rs index 16536b53..64430125 100644 --- a/crates/prometeu-core/src/firmware/firmware_step_reset.rs +++ b/crates/prometeu-core/src/firmware/firmware_step_reset.rs @@ -1,4 +1,5 @@ -use crate::firmware::firmware_state::{FirmwareState, SplashScreenStep}; +use crate::firmware::boot_target::BootTarget; +use crate::firmware::firmware_state::{FirmwareState, LaunchHubStep, SplashScreenStep}; use crate::firmware::prometeu_context::PrometeuContext; use crate::log::{LogLevel, LogSource}; @@ -11,8 +12,11 @@ impl ResetStep { ctx.os.reset(ctx.vm); } - pub fn on_update(&mut self, _ctx: &mut PrometeuContext) -> Option { - Some(FirmwareState::SplashScreen(SplashScreenStep { frame: 0 })) + pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option { + match ctx.boot_target { + BootTarget::Hub => Some(FirmwareState::SplashScreen(SplashScreenStep { frame: 0 })), + BootTarget::Cartridge { .. } => Some(FirmwareState::LaunchHub(LaunchHubStep)), + } } pub fn on_exit(&mut self, _ctx: &mut PrometeuContext) {} diff --git a/crates/prometeu-core/src/firmware/mod.rs b/crates/prometeu-core/src/firmware/mod.rs index c4a223ca..48f750dc 100644 --- a/crates/prometeu-core/src/firmware/mod.rs +++ b/crates/prometeu-core/src/firmware/mod.rs @@ -1,5 +1,6 @@ mod firmware; pub mod firmware_state; +mod boot_target; pub(crate) mod firmware_step_reset; pub(crate) mod firmware_step_splash_screen; @@ -13,3 +14,4 @@ mod prometeu_context; pub use firmware::Firmware; pub use firmware_state::FirmwareState; pub use prometeu_context::PrometeuContext; +pub use boot_target::BootTarget; diff --git a/crates/prometeu-core/src/firmware/prometeu_context.rs b/crates/prometeu-core/src/firmware/prometeu_context.rs index 80ca2686..00c40b7b 100644 --- a/crates/prometeu-core/src/firmware/prometeu_context.rs +++ b/crates/prometeu-core/src/firmware/prometeu_context.rs @@ -1,3 +1,4 @@ +use crate::firmware::boot_target::BootTarget; use crate::hardware::{HardwareBridge, InputSignals}; use crate::prometeu_hub::PrometeuHub; use crate::prometeu_os::PrometeuOS; @@ -7,6 +8,7 @@ pub struct PrometeuContext<'a> { pub vm: &'a mut VirtualMachine, pub os: &'a mut PrometeuOS, pub hub: &'a mut PrometeuHub, + pub boot_target: &'a BootTarget, pub signals: &'a InputSignals, pub hw: &'a mut dyn HardwareBridge, } \ No newline at end of file