paiagram/rw_data/
custom.rs1use crate::{
5 graph::{Graph, Station},
6 rw_data::ModifyData,
7 units::{distance::Distance, time::TimetableTime},
8 vehicles::{
9 entries::{TimetableEntry, TravelMode, VehicleSchedule},
10 vehicle_set::VehicleSet,
11 },
12};
13use bevy::{platform::collections::HashMap, prelude::*};
14use moonshine_core::kind::*;
15use serde::Deserialize;
16use serde_json;
17
18#[derive(Deserialize)]
19struct Root {
20 #[serde(rename = "工作日")]
21 weekday: HashMap<String, LineMeta>,
22 #[serde(rename = "双休日")]
23 holiday: HashMap<String, LineMeta>,
24}
25
26#[derive(Deserialize)]
27struct LineMeta(HashMap<String, HashMap<String, Vec<TrainInfo>>>);
28
29#[derive(Deserialize)]
30struct TrainInfo((String, String));
31
32pub fn load_qetrc(
33 mut commands: Commands,
34 mut reader: MessageReader<ModifyData>,
35 mut graph: ResMut<Graph>,
36) {
37 let mut str: Option<&str> = None;
38 for modification in reader.read() {
39 match modification {
40 ModifyData::LoadCustom(s) => str = Some(s.as_str()),
41 _ => {}
42 }
43 }
44 let Some(str) = str else {
45 return;
46 };
47 let root: Root = match serde_json::from_str(str) {
48 Ok(r) => r,
49 Err(e) => {
50 error!("Failed to parse custom data: {}", e);
51 return;
52 }
53 };
54 info!("Reading...");
55 let mut station_map: HashMap<String, Instance<Station>> = HashMap::new();
56 let vehicle_set: Entity = commands
57 .spawn((VehicleSet, Name::new("New vehicle set")))
58 .id();
59 for (line_name, line_meta) in root.weekday.into_iter().chain(root.holiday.into_iter()) {
60 for (train_number, train_info) in line_meta.0.into_iter().flat_map(|(_, d)| d.into_iter()) {
61 let get_interval = |commands: &mut Commands,
62 graph: &mut Graph,
63 from: Instance<Station>,
64 to: Instance<Station>| {
65 if let Some(&weight) = graph.edge_weight(from, to) {
66 return weight;
67 };
68 let interval_entity = commands
69 .spawn(Name::new(format!(
70 "Interval {} - {}",
71 from.entity().index(),
72 to.entity().index()
73 )))
74 .insert_instance(crate::graph::Interval {
75 length: Distance(1000),
76 speed_limit: None,
77 })
78 .into();
79 graph.add_edge(from, to, interval_entity);
80 interval_entity
81 };
82 let mut get_station = |commands: &mut Commands, graph: &mut Graph, name: String| {
83 if let Some(&entity) = station_map.get(&name) {
84 return entity;
85 }
86 let station_entity = commands
87 .spawn(Name::new(name.clone()))
88 .insert_instance(crate::graph::Station::default())
89 .into();
90 station_map.insert(name, station_entity);
91 graph.add_node(station_entity);
92 station_entity
93 };
94 let mut vehicle_schedule: Vec<Entity> = Vec::new();
95 let mut times: Vec<(String, TimetableTime)> = Vec::new();
96 let mut previous_station: Option<Instance<Station>> = None;
97 let vehicle_entity = commands
98 .spawn((crate::vehicles::Vehicle, Name::new(train_number)))
99 .id();
100 for TrainInfo((station_name, time)) in train_info {
101 let stripped_time = time.strip_prefix("(").unwrap_or(&time);
102 let stripped_time = stripped_time.strip_suffix("-").unwrap_or(stripped_time);
103 let Some(timetable_time) = TimetableTime::from_str(stripped_time) else {
104 warn!("Invalid time format: {}", time);
105 continue;
106 };
107 times.push((station_name, timetable_time));
108 }
109 super::normalize_times(times.iter_mut().map(|(_, t)| t));
110 for (station_name, timetable_time) in times {
111 let station_entity = get_station(&mut commands, &mut graph, station_name);
112 if let Some(previous_station) = previous_station {
113 let _ =
114 get_interval(&mut commands, &mut graph, previous_station, station_entity);
115 let _ =
116 get_interval(&mut commands, &mut graph, station_entity, previous_station);
117 }
118 previous_station = Some(station_entity);
119 let entry_entity = commands
120 .spawn((TimetableEntry {
121 station: station_entity.entity(),
122 arrival: TravelMode::At(timetable_time),
123 departure: Some(TravelMode::Flexible),
124 service: None,
125 track: None,
126 },))
127 .id();
128 vehicle_schedule.push(entry_entity);
129 commands.entity(vehicle_entity).add_child(entry_entity);
130 }
131 commands.entity(vehicle_entity).insert(VehicleSchedule {
132 entities: vehicle_schedule,
133 ..Default::default()
134 });
135 commands.entity(vehicle_set).add_child(vehicle_entity);
136 }
137 }
138}