136 lines
4.7 KiB
Rust
136 lines
4.7 KiB
Rust
use crate::firmware::firmware_state::{
|
|
AppCrashesStep, FirmwareState, GameRunningStep, HubHomeStep, ShellRunningStep,
|
|
};
|
|
use crate::firmware::prometeu_context::PrometeuContext;
|
|
use crate::firmware::resident_game_termination;
|
|
use prometeu_hal::app_mode::AppMode;
|
|
use prometeu_hal::cartridge::Cartridge;
|
|
use prometeu_hal::color::Color;
|
|
use prometeu_hal::log::{LogLevel, LogSource};
|
|
use prometeu_hal::primitives::Rect;
|
|
use prometeu_system::CrashReport;
|
|
use prometeu_system::windows::WindowOwner;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct LoadCartridgeStep {
|
|
pub cartridge: Cartridge,
|
|
init_error: Option<CrashReport>,
|
|
loaded_task_id: Option<prometeu_system::task::TaskId>,
|
|
loaded_app_mode: Option<AppMode>,
|
|
failure_recovery: LoadCartridgeFailureRecovery,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
enum LoadCartridgeFailureRecovery {
|
|
AppCrash,
|
|
ReturnToHub,
|
|
}
|
|
|
|
impl LoadCartridgeStep {
|
|
pub fn new(cartridge: Cartridge) -> Self {
|
|
Self {
|
|
cartridge,
|
|
init_error: None,
|
|
loaded_task_id: None,
|
|
loaded_app_mode: None,
|
|
failure_recovery: LoadCartridgeFailureRecovery::AppCrash,
|
|
}
|
|
}
|
|
|
|
pub fn new_game_switch(cartridge: Cartridge) -> Self {
|
|
Self { failure_recovery: LoadCartridgeFailureRecovery::ReturnToHub, ..Self::new(cartridge) }
|
|
}
|
|
|
|
pub fn on_enter(&mut self, ctx: &mut PrometeuContext) {
|
|
ctx.os.log(
|
|
LogLevel::Info,
|
|
LogSource::Pos,
|
|
0,
|
|
format!("Loading cartridge: {}", self.cartridge.title),
|
|
);
|
|
|
|
ctx.platform.game2d_frame_composer().unbind_scene();
|
|
|
|
// Initialize Asset Manager
|
|
ctx.platform.assets_mut().initialize_for_cartridge(
|
|
self.cartridge.asset_table.clone(),
|
|
self.cartridge.preload.clone(),
|
|
self.cartridge.assets.clone(),
|
|
);
|
|
|
|
match ctx.os.sessions().load_vm_cartridge(&self.cartridge) {
|
|
Ok(loaded) => {
|
|
self.loaded_task_id = Some(loaded.task_id);
|
|
self.loaded_app_mode = Some(loaded.app_mode);
|
|
}
|
|
Err(report) => {
|
|
self.init_error = Some(report.into_crash_report("load VM cartridge into session"));
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
|
if let Some(report) = self.init_error.take() {
|
|
if self.failure_recovery == LoadCartridgeFailureRecovery::ReturnToHub {
|
|
if self.cartridge.app_mode == AppMode::Game
|
|
&& let Some(task_id) = ctx.os.lifecycle().resident_game_task()
|
|
{
|
|
let is_partial_target = ctx
|
|
.os
|
|
.sessions()
|
|
.vm_session_for_task(task_id)
|
|
.map(|session| session.app_id == self.cartridge.app_id)
|
|
.unwrap_or(false);
|
|
|
|
if is_partial_target {
|
|
let _ = resident_game_termination::terminate_resident_game(
|
|
ctx.os,
|
|
ctx.platform,
|
|
false,
|
|
);
|
|
}
|
|
}
|
|
|
|
ctx.os.log(
|
|
LogLevel::Error,
|
|
LogSource::Hub,
|
|
0,
|
|
format!(
|
|
"Failed to switch to game {} app_id {}; returning to Home: {:?}",
|
|
self.cartridge.title, self.cartridge.app_id, report
|
|
),
|
|
);
|
|
return Some(FirmwareState::HubHome(HubHomeStep));
|
|
}
|
|
|
|
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
|
}
|
|
|
|
let Some(task_id) = self.loaded_task_id.take() else {
|
|
let report = CrashReport::VmPanic {
|
|
message: format!(
|
|
"cartridge {} was not loaded into a VM session",
|
|
self.cartridge.title
|
|
),
|
|
pc: None,
|
|
};
|
|
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
|
};
|
|
|
|
if self.loaded_app_mode == Some(AppMode::Shell) {
|
|
let id = ctx.os.windows().add_window(
|
|
self.cartridge.title.clone(),
|
|
WindowOwner::Task(task_id),
|
|
Rect { x: 40, y: 20, w: 240, h: 140 },
|
|
Color::WHITE,
|
|
);
|
|
ctx.os.windows().set_focus(id);
|
|
return Some(FirmwareState::ShellRunning(ShellRunningStep::new(task_id)));
|
|
}
|
|
|
|
Some(FirmwareState::GameRunning(GameRunningStep::new(task_id)))
|
|
}
|
|
|
|
pub fn on_exit(&mut self, _ctx: &mut PrometeuContext) {}
|
|
}
|