1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::{Scenario, ScenarioModifier, Sim, SimOptions};
use abstutil::CmdArgs;
use map_model::{Map, MapEdits};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

#[derive(Clone)]
pub struct SimFlags {
    pub load: String,
    pub modifiers: Vec<ScenarioModifier>,
    pub rng_seed: u8,
    pub opts: SimOptions,
}

impl SimFlags {
    pub const RNG_SEED: u8 = 42;

    pub fn from_args(args: &mut CmdArgs) -> SimFlags {
        let rng_seed = args
            .optional_parse("--rng_seed", |s| s.parse())
            .unwrap_or(SimFlags::RNG_SEED);
        SimFlags {
            load: args
                .optional_free()
                .unwrap_or_else(|| abstutil::path_map("montlake")),
            modifiers: Vec::new(),
            rng_seed,
            opts: SimOptions::from_args(args, rng_seed),
        }
    }

    // TODO rename seattle_test
    pub fn for_test(run_name: &str) -> SimFlags {
        SimFlags::synthetic_test("montlake", run_name)
    }

    pub fn synthetic_test(map: &str, run_name: &str) -> SimFlags {
        SimFlags {
            load: abstutil::path_map(map),
            modifiers: Vec::new(),
            rng_seed: SimFlags::RNG_SEED,
            opts: SimOptions::new(run_name),
        }
    }

    pub fn make_rng(&self) -> XorShiftRng {
        XorShiftRng::from_seed([self.rng_seed; 16])
    }

    // Convenience method to setup everything.
    pub fn load(&self, timer: &mut abstutil::Timer) -> (Map, Sim, XorShiftRng) {
        let mut rng = self.make_rng();

        let mut opts = self.opts.clone();

        if self.load.starts_with(&abstutil::path("player/saves/")) {
            timer.note(format!("Resuming from {}", self.load));

            let mut sim: Sim = abstutil::read_binary(self.load.clone(), timer);

            let mut map = Map::new(abstutil::path_map(&sim.map_name), timer);
            match MapEdits::load(
                &map,
                abstutil::path_edits(map.get_name(), &sim.edits_name),
                timer,
            ) {
                Ok(edits) => {
                    map.must_apply_edits(edits, timer);
                    map.recalculate_pathfinding_after_edits(timer);
                }
                Err(err) => {
                    // Little brittle. Sometimes legitimate edits wind up being saved without a
                    // proper name.
                    if sim.edits_name.starts_with("Untitled Proposal") {
                        warn!(
                            "Sim savestate refers to edits \"{}\", but not using them: {}",
                            sim.edits_name, err
                        );
                    } else {
                        panic!("Couldn't load edits \"{}\": {}", sim.edits_name, err);
                    }
                }
            }
            sim.restore_paths(&map, timer);

            (map, sim, rng)
        } else if self.load.starts_with(&abstutil::path("system/scenarios/")) {
            timer.note(format!(
                "Seeding the simulation from scenario {}",
                self.load
            ));

            let mut scenario: Scenario = abstutil::read_binary(self.load.clone(), timer);

            let map = Map::new(abstutil::path_map(&scenario.map_name), timer);

            let mut modifier_rng = self.make_rng();
            for m in &self.modifiers {
                scenario = m.apply(&map, scenario, &mut modifier_rng);
            }

            if opts.run_name == "unnamed" {
                opts.run_name = scenario.scenario_name.clone();
            }
            let mut sim = Sim::new(&map, opts, timer);
            scenario.instantiate(&mut sim, &map, &mut rng, timer);

            (map, sim, rng)
        } else if self.load.starts_with(&abstutil::path_all_raw_maps())
            || self.load.starts_with(&abstutil::path_all_synthetic_maps())
            || self.load.starts_with(&abstutil::path_all_maps())
        {
            timer.note(format!("Loading map {}", self.load));

            let map = Map::new(self.load.clone(), timer);

            timer.start("create sim");
            let sim = Sim::new(&map, opts, timer);
            timer.stop("create sim");

            (map, sim, rng)
        } else {
            panic!("Don't know how to load {}", self.load);
        }
    }
}