diff --git a/Cargo.lock b/Cargo.lock index 4990382..dab0b79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ab_glyph" @@ -2200,6 +2200,12 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "oneshot" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" + [[package]] name = "orbclient" version = "0.3.48" @@ -2684,6 +2690,7 @@ dependencies = [ "itertools", "num-derive", "num-traits", + "oneshot", "pollster 0.4.0", "rfd", "rtrb", diff --git a/Cargo.toml b/Cargo.toml index 2db1fb7..9cb8ffa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ gilrs = "0.11" itertools = "0.13" num-derive = "0.4" num-traits = "0.2" +oneshot = "0.1" pollster = "0.4" rfd = "0.15" rtrb = "0.3" diff --git a/src/app.rs b/src/app.rs index 19aa2b6..052cf32 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, num::NonZero, sync::Arc, thread}; +use std::{collections::HashSet, num::NonZero, sync::Arc, thread, time::Duration}; use egui::{ ahash::{HashMap, HashMapExt}, @@ -15,7 +15,7 @@ use winit::{ use crate::{ controller::ControllerManager, - emulator::{EmulatorClient, SimId}, + emulator::{EmulatorClient, EmulatorCommand, SimId}, input::MappingProvider, window::{AppWindow, GameWindow, InputWindow}, }; @@ -170,6 +170,15 @@ impl ApplicationHandler for Application { viewport.window.request_redraw(); } } + + fn exiting(&mut self, _event_loop: &ActiveEventLoop) { + let (sender, receiver) = oneshot::channel(); + if self.client.send_command(EmulatorCommand::Exit(sender)) { + if let Err(err) = receiver.recv_timeout(Duration::from_secs(5)) { + eprintln!("could not gracefully exit: {}", err); + } + } + } } struct Viewport { diff --git a/src/emulator.rs b/src/emulator.rs index 00cb318..f012196 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -186,6 +186,8 @@ impl Emulator { } fn reset_sim(&mut self, sim_id: SimId, new_cart: Option) -> Result<()> { + self.save_sram(sim_id)?; + let index = sim_id.to_index(); while self.sims.len() <= index { self.sims.push(Sim::new()); @@ -226,6 +228,10 @@ impl Emulator { pub fn pause_sim(&mut self, sim_id: SimId) -> Result<()> { self.running[sim_id.to_index()].store(false, Ordering::Release); + self.save_sram(sim_id) + } + + fn save_sram(&mut self, sim_id: SimId) -> Result<()> { let sim = self.sims.get_mut(sim_id.to_index()); let cart = self.carts[sim_id.to_index()].as_mut(); if let (Some(sim), Some(cart)) = (sim, cart) { @@ -236,13 +242,15 @@ impl Emulator { Ok(()) } - pub fn stop_second_sim(&mut self) { + pub fn stop_second_sim(&mut self) -> Result<()> { + self.save_sram(SimId::Player2)?; self.renderers.remove(&SimId::Player2); self.sims.truncate(1); self.sim_count.store(self.sims.len(), Ordering::Relaxed); self.running[SimId::Player2.to_index()].store(false, Ordering::Release); self.has_game[SimId::Player2.to_index()].store(false, Ordering::Release); self.linked.store(false, Ordering::Release); + Ok(()) } pub fn run(&mut self) { @@ -336,7 +344,9 @@ impl Emulator { } } EmulatorCommand::StopSecondSim => { - self.stop_second_sim(); + if let Err(error) = self.stop_second_sim() { + eprintln!("error stopping second sim: {}", error); + } } EmulatorCommand::Pause => { for sim_id in SimId::values() { @@ -373,6 +383,14 @@ impl Emulator { sim.set_keys(keys); } } + EmulatorCommand::Exit(done) => { + for sim_id in SimId::values() { + if let Err(error) = self.save_sram(sim_id) { + eprintln!("error saving sram on exit: {}", error); + } + } + let _ = done.send(()); + } } } } @@ -390,6 +408,7 @@ pub enum EmulatorCommand { Unlink, Reset(SimId), SetKeys(SimId, VBKey), + Exit(oneshot::Sender<()>), } #[derive(Clone)] @@ -418,12 +437,16 @@ impl EmulatorClient { pub fn is_audio_enabled(&self, sim_id: SimId) -> bool { self.audio_on[sim_id.to_index()].load(Ordering::Acquire) } - pub fn send_command(&self, command: EmulatorCommand) { - if let Err(err) = self.queue.send(command) { - eprintln!( - "could not send command {:?} as emulator is shut down", - err.0 - ); + pub fn send_command(&self, command: EmulatorCommand) -> bool { + match self.queue.send(command) { + Ok(()) => true, + Err(err) => { + eprintln!( + "could not send command {:?} as emulator is shut down", + err.0 + ); + false + } } } }