1use anyhow::Result;
2use rand::SeedableRng;
3use rand_xorshift::XorShiftRng;
4use structopt::StructOpt;
5
6use abstio::MapName;
7use map_model::{Map, MapEdits};
8use synthpop::{Scenario, ScenarioModifier};
9
10use crate::{Sim, SimOptions};
11
12#[derive(Clone, StructOpt)]
15pub struct SimFlags {
16 #[structopt()]
22 load_path: Option<String>,
23 #[structopt(skip)]
26 pub load: String,
27 #[structopt(long, parse(try_from_str = parse_modifiers), default_value = "[]")]
29 pub scenario_modifiers: ModifierList,
30 #[structopt(long, default_value = "42")]
34 pub rng_seed: u64,
35 #[structopt(flatten)]
36 pub opts: SimOptions,
37}
38
39type ModifierList = Vec<ScenarioModifier>;
41
42fn parse_modifiers(x: &str) -> Result<ModifierList> {
43 abstutil::from_json(&x.to_string().into_bytes())
44}
45
46impl SimFlags {
47 pub const RNG_SEED: u64 = 42;
48
49 pub fn initialize(&mut self) {
50 self.load = self
52 .load_path
53 .clone()
54 .unwrap_or_else(|| MapName::seattle("montlake").path());
55 }
56
57 pub fn for_test(run_name: &str) -> SimFlags {
59 SimFlags {
60 load_path: None,
61 load: MapName::seattle("montlake").path(),
62 scenario_modifiers: Vec::new(),
63 rng_seed: SimFlags::RNG_SEED,
64 opts: SimOptions::new(run_name),
65 }
66 }
67
68 pub fn make_rng(&self) -> XorShiftRng {
69 XorShiftRng::seed_from_u64(self.rng_seed)
70 }
71
72 pub fn load_synchronously(&self, timer: &mut abstutil::Timer) -> (Map, Sim, XorShiftRng) {
74 if self.load.is_empty() {
75 panic!("You forgot to call initialize on SimFlags after parsing from structopt");
76 }
77
78 let mut rng = self.make_rng();
79
80 let mut opts = self.opts.clone();
81
82 if self.load.starts_with(&abstio::path_player("saves/")) {
83 info!("Resuming from {}", self.load);
84
85 let sim: Sim = abstio::must_read_object(self.load.clone(), timer);
86
87 let mut map = Map::load_synchronously(sim.map_name.path(), timer);
88 match MapEdits::load_from_file(
89 &map,
90 abstio::path_edits(map.get_name(), &sim.edits_name),
91 timer,
92 ) {
93 Ok(edits) => {
94 map.must_apply_edits(edits, timer);
95 map.recalculate_pathfinding_after_edits(timer);
96 }
97 Err(err) => {
98 panic!("Couldn't load edits \"{}\": {}", sim.edits_name, err);
99 }
100 }
101
102 (map, sim, rng)
103 } else if self.load.contains("/scenarios/") {
104 info!("Seeding the simulation from scenario {}", self.load);
105
106 let mut scenario: Scenario = abstio::must_read_object(self.load.clone(), timer);
107
108 let map = Map::load_synchronously(scenario.map_name.path(), timer);
109
110 for m in &self.scenario_modifiers {
111 scenario = m.apply(&map, scenario, &mut rng);
112 }
113
114 if opts.run_name == "unnamed" {
115 opts.run_name = scenario.scenario_name.clone();
116 }
117 let mut sim = Sim::new(&map, opts);
118 sim.instantiate(&scenario, &map, &mut rng, timer);
119
120 (map, sim, rng)
121 } else if self.load.contains("/raw_maps/") || self.load.contains("/maps/") {
122 info!("Loading map {}", self.load);
123
124 let map = Map::load_synchronously(self.load.clone(), timer);
125
126 timer.start("create sim");
127 let sim = Sim::new(&map, opts);
128 timer.stop("create sim");
129
130 (map, sim, rng)
131 } else {
132 panic!("Don't know how to load {}", self.load);
133 }
134 }
135}