Choose save data location

This commit is contained in:
2026-09-06 21:30:46 -04:00
parent 7d517e932e
commit e2c25cbae5
9 changed files with 234 additions and 117 deletions
+72 -44
View File
@@ -18,6 +18,7 @@ use tracing::{error, warn};
use crate::{
audio::Audio,
config::SaveDataLocation,
graphics::TextureSink,
memory::{MemoryRange, MemoryRegion},
};
@@ -74,12 +75,13 @@ pub struct EmulatorBuilder {
state: Arc<Atomic<EmulatorState>>,
audio_on: Arc<[AtomicBool; 2]>,
linked: Arc<AtomicBool>,
save_data_location: Arc<Atomic<SaveDataLocation>>,
start_paused: bool,
watch_rom: Arc<[AtomicBool; 2]>,
}
impl EmulatorBuilder {
pub fn new() -> (Self, EmulatorClient) {
pub fn new(save_data_location: SaveDataLocation) -> (Self, EmulatorClient) {
let (queue, commands) = mpsc::channel();
let builder = Self {
rom: None,
@@ -91,6 +93,7 @@ impl EmulatorBuilder {
state: Arc::new(Atomic::new(EmulatorState::Paused)),
audio_on: Arc::new([AtomicBool::new(true), AtomicBool::new(true)]),
linked: Arc::new(AtomicBool::new(false)),
save_data_location: Arc::new(Atomic::new(save_data_location)),
start_paused: false,
watch_rom: Arc::new([AtomicBool::new(false), AtomicBool::new(false)]),
};
@@ -98,8 +101,9 @@ impl EmulatorBuilder {
queue,
sim_state: builder.sim_state.clone(),
state: builder.state.clone(),
watch_rom: builder.watch_rom.clone(),
linked: builder.linked.clone(),
save_data_location: builder.save_data_location.clone(),
watch_rom: builder.watch_rom.clone(),
};
(builder, client)
}
@@ -131,18 +135,42 @@ impl EmulatorBuilder {
}
pub fn build(self) -> Result<Emulator> {
let mut emulator = Emulator::new(
self.commands,
self.sim_state,
self.state,
self.audio_on,
self.watch_rom,
self.linked,
);
if let Some(path) = self.rom {
let Self {
rom,
commands,
sim_state,
state,
audio_on,
watch_rom,
linked,
save_data_location,
start_paused,
} = self;
let mut emulator = Emulator {
sims: vec![],
carts: [None, None],
audio: Audio::init(),
commands,
sim_state,
state,
audio_on,
watch_rom,
linked,
save_data_location,
profilers: [None, None],
renderers: HashMap::new(),
messages: HashMap::new(),
debuggers: HashMap::new(),
stdouts: HashMap::new(),
watched_regions: HashMap::new(),
eye_contents: [vec![0u8; 384 * 224 * 2], vec![0u8; 384 * 224 * 2]],
audio_samples: Vec::with_capacity(EXPECTED_FRAME_SIZE),
buffer: vec![],
};
if let Some(path) = rom {
emulator.load_cart(SimId::Player1, &path)?;
}
if self.start_paused {
if start_paused {
emulator.pause_sims()?;
}
Ok(emulator)
@@ -159,6 +187,7 @@ pub struct Emulator {
audio_on: Arc<[AtomicBool; 2]>,
watch_rom: Arc<[AtomicBool; 2]>,
linked: Arc<AtomicBool>,
save_data_location: Arc<Atomic<SaveDataLocation>>,
profilers: [Option<ProfileSender>; 2],
renderers: HashMap<SimId, TextureSink>,
messages: HashMap<SimId, mpsc::Sender<Toast>>,
@@ -171,36 +200,6 @@ pub struct Emulator {
}
impl Emulator {
fn new(
commands: mpsc::Receiver<EmulatorCommand>,
sim_state: Arc<[Atomic<SimState>; 2]>,
state: Arc<Atomic<EmulatorState>>,
audio_on: Arc<[AtomicBool; 2]>,
watch_rom: Arc<[AtomicBool; 2]>,
linked: Arc<AtomicBool>,
) -> Self {
Self {
sims: vec![],
carts: [None, None],
audio: Audio::init(),
commands,
sim_state,
state,
audio_on,
watch_rom,
linked,
profilers: [None, None],
renderers: HashMap::new(),
messages: HashMap::new(),
debuggers: HashMap::new(),
stdouts: HashMap::new(),
watched_regions: HashMap::new(),
eye_contents: [vec![0u8; 384 * 224 * 2], vec![0u8; 384 * 224 * 2]],
audio_samples: Vec::with_capacity(EXPECTED_FRAME_SIZE),
buffer: vec![],
}
}
pub fn reload_cart(&mut self, sim_id: SimId) -> Result<()> {
let Some(cart) = &self.carts[sim_id.to_index()] else {
return Ok(());
@@ -211,7 +210,12 @@ impl Emulator {
pub fn load_cart(&mut self, sim_id: SimId, path: &Path) -> Result<()> {
let watch = self.watch_rom[sim_id.to_index()].load(Ordering::Acquire);
let cart = Cart::load(path, sim_id, watch)?;
let cart = Cart::load(
path,
sim_id,
self.save_data_location.load(Ordering::Acquire),
watch,
)?;
self.try_reset_sim(sim_id, Some(cart))?;
Ok(())
}
@@ -224,7 +228,12 @@ impl Emulator {
};
let watch = self.watch_rom[SimId::Player2.to_index()].load(Ordering::Acquire);
let cart = match file_path {
Some(rom_path) => Some(Cart::load(&rom_path, SimId::Player2, watch)?),
Some(rom_path) => Some(Cart::load(
&rom_path,
SimId::Player2,
self.save_data_location.load(Ordering::Acquire),
watch,
)?),
None => None,
};
self.try_reset_sim(SimId::Player2, cart)?;
@@ -687,6 +696,20 @@ impl Emulator {
cart.stop_watching();
}
}
EmulatorCommand::SetSaveDataLocation(save_data_location) => {
self.save_data_location
.store(save_data_location, Ordering::Release);
for sim_id in SimId::values() {
if let Some(cart) = self.carts[sim_id.to_index()].as_mut()
&& let Err(error) = cart.change_save_data_location(save_data_location)
{
self.report_error(
sim_id,
format!("Error changing save data location: {error}"),
);
}
}
}
EmulatorCommand::StartSecondSim(path) => {
if let Err(error) = self.start_second_sim(path) {
self.report_error(
@@ -854,6 +877,7 @@ pub enum EmulatorCommand {
LoadGame(SimId, PathBuf),
ReloadRom(SimId),
WatchRom(SimId, bool),
SetSaveDataLocation(SaveDataLocation),
StartSecondSim(Option<PathBuf>),
StopSecondSim,
Pause,
@@ -943,6 +967,7 @@ pub struct EmulatorClient {
sim_state: Arc<[Atomic<SimState>; 2]>,
state: Arc<Atomic<EmulatorState>>,
linked: Arc<AtomicBool>,
save_data_location: Arc<Atomic<SaveDataLocation>>,
watch_rom: Arc<[AtomicBool; 2]>,
}
@@ -959,6 +984,9 @@ impl EmulatorClient {
pub fn are_sims_linked(&self) -> bool {
self.linked.load(Ordering::Acquire)
}
pub fn save_data_location(&self) -> SaveDataLocation {
self.save_data_location.load(Ordering::Acquire)
}
pub fn is_rom_watched(&self, sim_id: SimId) -> bool {
self.watch_rom[sim_id.to_index()].load(Ordering::Acquire)
}