game/sandbox/gameplay/freeform/
importers.rs1use anyhow::Result;
4use serde::Deserialize;
5
6use abstutil::Timer;
7use map_gui::tools::{find_exe, FilePicker, RunCommand};
8use map_model::Map;
9use synthpop::{ExternalPerson, Scenario};
10use widgetry::tools::PopupMsg;
11use widgetry::EventCtx;
12
13use crate::app::Transition;
14use crate::sandbox::gameplay::GameplayMode;
15use crate::sandbox::SandboxMode;
16
17pub fn import_grid2demand(ctx: &mut EventCtx) -> Transition {
18 Transition::Push(FilePicker::new_state(
19 ctx,
20 None,
21 Box::new(|ctx, app, maybe_file| {
22 if let Ok(Some((path, _))) = maybe_file {
23 Transition::Replace(RunCommand::new_state(
24 ctx,
25 true,
26 vec![
27 find_exe("cli"),
28 "import-grid2-demand".to_string(),
29 format!("--map={}", app.primary.map.get_name().path()),
30 format!("--input={}", path),
31 ],
32 Box::new(|_, app, success, _| {
33 if success {
34 app.primary.scenario = None;
37 Transition::Replace(SandboxMode::simple_new(
38 app,
39 GameplayMode::PlayScenario(
40 app.primary.map.get_name().clone(),
41 "grid2demand".to_string(),
42 Vec::new(),
43 ),
44 ))
45 } else {
46 Transition::Keep
48 }
49 }),
50 ))
51 } else {
52 Transition::Pop
54 }
55 }),
56 ))
57}
58
59pub fn import_json(ctx: &mut EventCtx) -> Transition {
60 Transition::Push(FilePicker::new_state(
61 ctx,
62 None,
63 Box::new(|ctx, app, maybe_file| {
64 if let Ok(Some((_, bytes))) = maybe_file {
65 let result = ctx.loading_screen("import JSON scenario", |_, timer| {
66 import_json_scenario(&app.primary.map, bytes, timer)
67 });
68 match result {
69 Ok(scenario_name) => {
70 app.primary.scenario = None;
73 Transition::Replace(SandboxMode::simple_new(
74 app,
75 GameplayMode::PlayScenario(
76 app.primary.map.get_name().clone(),
77 scenario_name,
78 Vec::new(),
79 ),
80 ))
81 }
82 Err(err) => Transition::Replace(PopupMsg::new_state(
83 ctx,
84 "Error",
85 vec![err.to_string()],
86 )),
87 }
88 } else {
89 Transition::Pop
91 }
92 }),
93 ))
94}
95
96fn import_json_scenario(map: &Map, bytes: Vec<u8>, timer: &mut Timer) -> Result<String> {
99 let skip_problems = true;
100 let input: Input = abstutil::from_json(&bytes)?;
101
102 let mut s = Scenario::empty(map, &input.scenario_name);
103 s.only_seed_buses = None;
105 timer.start("import from JSON");
106 s.people = ExternalPerson::import(map, input.people, skip_problems)?;
107 s = s.remove_weird_schedules(true);
109 timer.stop("import from JSON");
110 s.save();
111 Ok(s.scenario_name)
112}
113
114#[derive(Deserialize)]
115struct Input {
116 scenario_name: String,
117 people: Vec<ExternalPerson>,
118}