fix resident game relaunch from hub
This commit is contained in:
parent
a517a24978
commit
e19409a2ef
@ -96,9 +96,14 @@ impl Firmware {
|
|||||||
signals: &InputSignals,
|
signals: &InputSignals,
|
||||||
platform: &mut dyn RuntimePlatform,
|
platform: &mut dyn RuntimePlatform,
|
||||||
) {
|
) {
|
||||||
|
let entering_game_from_home = matches!(self.state, FirmwareState::HubHome(_))
|
||||||
|
&& matches!(new_state, FirmwareState::GameRunning(_));
|
||||||
self.on_exit(signals, platform);
|
self.on_exit(signals, platform);
|
||||||
self.state = new_state;
|
self.state = new_state;
|
||||||
self.state_initialized = false;
|
self.state_initialized = false;
|
||||||
|
if entering_game_from_home {
|
||||||
|
self.game_input_barrier_frames = self.game_input_barrier_frames.max(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Enter the new state immediately to avoid "empty" frames during transitions.
|
// Enter the new state immediately to avoid "empty" frames during transitions.
|
||||||
self.on_enter(signals, platform);
|
self.on_enter(signals, platform);
|
||||||
@ -620,6 +625,60 @@ mod tests {
|
|||||||
assert_eq!(firmware.os.windows().window_count(), 0);
|
assert_eq!(firmware.os.windows().window_count(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hub_home_clicking_resident_game_resumes_same_task_without_reloading() {
|
||||||
|
let root = TestGameRoot::new();
|
||||||
|
root.add_game("stress", true);
|
||||||
|
|
||||||
|
let (mut firmware, mut platform) = hub_home_firmware();
|
||||||
|
firmware.hub.set_game_library(discover_games_root(&root.path));
|
||||||
|
firmware.tick(&InputSignals::default(), &mut platform);
|
||||||
|
|
||||||
|
let launch_click =
|
||||||
|
InputSignals { f_signal: true, x_pos: 72, y_pos: 90, ..Default::default() };
|
||||||
|
firmware.tick(&launch_click, &mut platform);
|
||||||
|
firmware.tick(&InputSignals::default(), &mut platform);
|
||||||
|
|
||||||
|
let game_task = match &firmware.state {
|
||||||
|
FirmwareState::GameRunning(step) => step.task_id,
|
||||||
|
other => panic!("expected GameRunning state, got {:?}", other),
|
||||||
|
};
|
||||||
|
|
||||||
|
firmware.request_home_from_host();
|
||||||
|
firmware.tick(&InputSignals::default(), &mut platform);
|
||||||
|
|
||||||
|
assert!(matches!(firmware.state, FirmwareState::HubHome(_)));
|
||||||
|
assert_eq!(firmware.os.lifecycle().resident_game_task(), Some(game_task));
|
||||||
|
assert_eq!(firmware.os.lifecycle().task_state(game_task), Some(TaskState::Suspended));
|
||||||
|
|
||||||
|
firmware.tick(&InputSignals::default(), &mut platform);
|
||||||
|
firmware.tick(&launch_click, &mut platform);
|
||||||
|
|
||||||
|
match &firmware.state {
|
||||||
|
FirmwareState::GameRunning(step) => assert_eq!(step.task_id, game_task),
|
||||||
|
other => panic!("expected resident GameRunning state, got {:?}", other),
|
||||||
|
}
|
||||||
|
assert_eq!(firmware.os.lifecycle().resident_game_task(), Some(game_task));
|
||||||
|
assert_eq!(firmware.os.lifecycle().foreground_owner(), ForegroundOwner::Game(game_task));
|
||||||
|
assert_eq!(firmware.os.lifecycle().task_state(game_task), Some(TaskState::Foreground));
|
||||||
|
assert_eq!(
|
||||||
|
firmware.os.lifecycle().pending_game_lifecycle_events().last().map(|event| event.kind),
|
||||||
|
Some(GameLifecycleEventKind::ResumeForeground)
|
||||||
|
);
|
||||||
|
|
||||||
|
let held_click =
|
||||||
|
InputSignals { f_signal: true, x_pos: 72, y_pos: 90, ..Default::default() };
|
||||||
|
firmware.tick(&held_click, &mut platform);
|
||||||
|
|
||||||
|
assert!(!platform.input().pad().any());
|
||||||
|
assert!(!platform.input().touch().f().down);
|
||||||
|
assert!(firmware.os.lifecycle().pending_game_lifecycle_events().is_empty());
|
||||||
|
assert_eq!(
|
||||||
|
firmware.os.vm().delivered_game_lifecycle_events().last().map(|event| event.kind),
|
||||||
|
Some(GameLifecycleEventKind::ResumeForeground)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_games_root_candidate_is_omitted_from_home_launch_boundary() {
|
fn invalid_games_root_candidate_is_omitted_from_home_launch_boundary() {
|
||||||
let root = TestGameRoot::new();
|
let root = TestGameRoot::new();
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
use crate::firmware::firmware_state::{
|
use crate::firmware::firmware_state::{
|
||||||
AppCrashesStep, FirmwareState, LoadCartridgeStep, ShellRunningStep,
|
AppCrashesStep, FirmwareState, GameRunningStep, LoadCartridgeStep, ShellRunningStep,
|
||||||
};
|
};
|
||||||
use crate::firmware::prometeu_context::PrometeuContext;
|
use crate::firmware::prometeu_context::PrometeuContext;
|
||||||
|
use prometeu_hal::InputSignals;
|
||||||
|
use prometeu_hal::app_mode::AppMode;
|
||||||
use prometeu_hal::cartridge_loader::CartridgeLoader;
|
use prometeu_hal::cartridge_loader::CartridgeLoader;
|
||||||
use prometeu_hal::log::{LogLevel, LogSource};
|
use prometeu_hal::log::{LogLevel, LogSource};
|
||||||
use prometeu_hal::primitives::Rect;
|
use prometeu_hal::primitives::Rect;
|
||||||
@ -38,6 +40,55 @@ impl HubHomeStep {
|
|||||||
}
|
}
|
||||||
Some(SystemProfileAction::LaunchGame { path }) => match CartridgeLoader::load(&path) {
|
Some(SystemProfileAction::LaunchGame { path }) => match CartridgeLoader::load(&path) {
|
||||||
Ok(cartridge) => {
|
Ok(cartridge) => {
|
||||||
|
if cartridge.app_mode == AppMode::Game
|
||||||
|
&& let Some(task_id) = ctx.os.lifecycle().resident_game_task()
|
||||||
|
{
|
||||||
|
if ctx.os.vm().current_app_id() == cartridge.app_id {
|
||||||
|
match ctx.os.lifecycle().resume_task(task_id) {
|
||||||
|
Ok(()) => {
|
||||||
|
ctx.os
|
||||||
|
.vm()
|
||||||
|
.transition_render_owner(AppMode::Game, cartridge.app_id);
|
||||||
|
ctx.platform
|
||||||
|
.input_mut()
|
||||||
|
.pad_mut()
|
||||||
|
.begin_frame(&InputSignals::default());
|
||||||
|
ctx.platform
|
||||||
|
.input_mut()
|
||||||
|
.touch_mut()
|
||||||
|
.begin_frame(&InputSignals::default());
|
||||||
|
return Some(FirmwareState::GameRunning(GameRunningStep::new(
|
||||||
|
task_id,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
ctx.os.log(
|
||||||
|
LogLevel::Warn,
|
||||||
|
LogSource::Hub,
|
||||||
|
0,
|
||||||
|
format!(
|
||||||
|
"Failed to resume resident Home game {}: {error:?}",
|
||||||
|
cartridge.title
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let resident_app_id = ctx.os.vm().current_app_id();
|
||||||
|
ctx.os.log(
|
||||||
|
LogLevel::Warn,
|
||||||
|
LogSource::Hub,
|
||||||
|
0,
|
||||||
|
format!(
|
||||||
|
"Cannot launch Home game {} while resident game app_id {} is active",
|
||||||
|
cartridge.title, resident_app_id
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
return Some(FirmwareState::LoadCartridge(LoadCartridgeStep::new(cartridge)));
|
return Some(FirmwareState::LoadCartridge(LoadCartridgeStep::new(cartridge)));
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user