diff --git a/editor/src/plugins/sim/controls.rs b/editor/src/plugins/sim/controls.rs index 1334f395f0..b20da426c7 100644 --- a/editor/src/plugins/sim/controls.rs +++ b/editor/src/plugins/sim/controls.rs @@ -3,7 +3,7 @@ use crate::plugins::{Plugin, PluginCtx}; use abstutil::elapsed_seconds; use ezgui::EventLoopMode; use piston::input::Key; -use sim::{Benchmark, TIMESTEP}; +use sim::{Benchmark, Sim, TIMESTEP}; use std::mem; use std::time::{Duration, Instant}; @@ -77,15 +77,51 @@ impl Plugin for SimControls { } if ctx .input - .unimportant_key_pressed(Key::P, SIM, "load sim state") + .unimportant_key_pressed(Key::Y, SIM, "load previous sim state") { - match ctx.primary.sim.load_most_recent() { + match ctx + .primary + .sim + .find_previous_savestate(ctx.primary.sim.time) + .and_then(|path| Sim::load_savestate(path, None)) + { + Ok(new_sim) => { + // TODO From the perspective of other SimMode plugins, does this just + // look like the simulation stepping forwards? + ctx.primary.sim = new_sim; + ctx.primary.recalculate_current_selection = true; + + if let Some((s, _)) = ctx.secondary { + s.sim = Sim::load_savestate( + s.sim.find_previous_savestate(s.sim.time).unwrap(), + None, + ) + .unwrap(); + } + } + Err(e) => error!("Couldn't load savestate: {}", e), + }; + } + if ctx + .input + .unimportant_key_pressed(Key::U, SIM, "load next sim state") + { + match ctx + .primary + .sim + .find_next_savestate(ctx.primary.sim.time) + .and_then(|path| Sim::load_savestate(path, None)) + { Ok(new_sim) => { ctx.primary.sim = new_sim; ctx.primary.recalculate_current_selection = true; if let Some((s, _)) = ctx.secondary { - s.sim = s.sim.load_most_recent().unwrap(); + s.sim = Sim::load_savestate( + s.sim.find_next_savestate(s.sim.time).unwrap(), + None, + ) + .unwrap(); } } Err(e) => error!("Couldn't load savestate: {}", e), diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 2c25e03c68..c3e1425a7c 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -88,9 +88,15 @@ impl Sim { } } - pub fn load(path: String, new_run_name: String) -> Result { + pub fn load_savestate( + path: String, + new_run_name: Option, + ) -> Result { + info!("Loading {}", path); abstutil::read_json(&path).map(|mut s: Sim| { - s.run_name = new_run_name; + if let Some(name) = new_run_name { + s.run_name = name; + } s }) } @@ -135,15 +141,8 @@ impl Sim { "At {} while processing {:?}", self.time, self.current_agent_for_debugging ); - if let Ok(mut list) = self.find_all_savestates() { - // Find the most recent one BEFORE the current time - list.reverse(); - for (tick, path) in list { - if tick < self.time { - error!("Debug from {}", path); - break; - } - } + if let Ok(path) = self.find_previous_savestate(self.time) { + error!("Debug from {}", path); } } @@ -313,15 +312,6 @@ impl Sim { path } - // TODO Return a descriptive error again - pub fn load_most_recent(&self) -> Result { - let (_, load) = self - .find_all_savestates() - .and_then(|mut list| list.pop().ok_or_else(|| io_error("empty directory")))?; - info!("Loading {}", load); - abstutil::read_json(&load) - } - // Earliest one is first fn find_all_savestates(&self) -> Result, std::io::Error> { let mut results: Vec<(Tick, String)> = Vec::new(); @@ -351,6 +341,28 @@ impl Sim { Ok(results) } + pub fn find_previous_savestate(&self, base_time: Tick) -> Result { + let mut list = self.find_all_savestates()?; + // Find the most recent one BEFORE the current time + list.reverse(); + for (tick, path) in list { + if tick < base_time { + return Ok(path); + } + } + Err(io_error(&format!("no savestate before {}", base_time))) + } + + pub fn find_next_savestate(&self, base_time: Tick) -> Result { + let list = self.find_all_savestates()?; + for (tick, path) in list { + if tick > base_time { + return Ok(path); + } + } + Err(io_error(&format!("no savestate after {}", base_time))) + } + pub fn active_agents(&self) -> Vec { self.trips_state.active_agents() } diff --git a/tests/src/sim_determinism.rs b/tests/src/sim_determinism.rs index 291c5073ee..92a9ac26a1 100644 --- a/tests/src/sim_determinism.rs +++ b/tests/src/sim_determinism.rs @@ -89,7 +89,8 @@ pub fn run(t: &mut TestRunner) { } let sim3: sim::Sim = - sim::Sim::load(sim1_save.clone(), "with_savestating_3".to_string()).unwrap(); + sim::Sim::load_savestate(sim1_save.clone(), Some("with_savestating_3".to_string())) + .unwrap(); if sim3 != sim2 { panic!( "sim state differs between {} and {}",