1use crate::graph::Station;
2use crate::vehicles::services::VehicleService;
3use bevy::prelude::*;
4use moonshine_core::kind::Instance;
5use moonshine_core::save::prelude::*;
6mod calculate_estimates;
7pub mod entries;
8pub mod services;
9pub mod vehicle_set;
10
11#[derive(Reflect, Debug, Component)]
12#[reflect(Component)]
13#[require(Name, entries::VehicleSchedule, Save)]
14pub struct Vehicle;
15
16pub struct VehiclesPlugin;
17
18impl Plugin for VehiclesPlugin {
19 fn build(&self, app: &mut App) {
20 app.add_message::<AdjustTimetableEntry>()
21 .add_message::<AdjustVehicle>()
22 .add_systems(
23 FixedUpdate,
24 (
25 adjust_timetable_entry,
26 entries::calculate_actual_route,
27 calculate_estimates::calculate_estimates,
28 entries::populate_services,
29 )
30 .chain()
31 .run_if(on_message::<AdjustTimetableEntry>),
32 );
33 }
34}
35
36#[derive(Debug)]
37pub enum TimetableAdjustment {
38 SetArrivalType(entries::TravelMode),
39 AdjustArrivalTime(crate::units::time::Duration),
40 SetDepartureType(Option<entries::TravelMode>),
41 AdjustDepartureTime(crate::units::time::Duration),
42 SetStation(Instance<Station>),
43 SetService(Option<Instance<VehicleService>>),
44 SetTrack(Option<Entity>),
45 SetNote(Option<String>),
46 PassThrough,
47}
48
49#[derive(Message, Debug)]
50pub struct AdjustTimetableEntry {
51 pub entity: Entity,
52 pub adjustment: TimetableAdjustment,
53}
54
55pub enum VehicleAdjustment {
56 AddEntry(usize, Entity),
57 RemoveEntry(Entity),
58 Rename(String),
59 Remove,
60}
61
62#[derive(Message)]
63pub struct AdjustVehicle {
64 pub entity: Entity,
65 pub adjustment: VehicleAdjustment,
66}
67
68pub fn adjust_timetable_entry(
69 mut commands: Commands,
70 mut reader: MessageReader<AdjustTimetableEntry>,
71 entries: Populated<&entries::TimetableEntry>,
72) {
73 for msg in reader.read() {
74 let AdjustTimetableEntry { entity, adjustment } = msg;
75 let entry = match entries.get(*entity) {
76 Ok(a) => a,
77 Err(e) => {
78 warn!("Failed to adjust timetable entry {entity:?}: {e:?}");
79 continue;
80 }
81 };
82 let mut new_entry = entry.clone();
83
84 use TimetableAdjustment::*;
85 match adjustment {
86 AdjustArrivalTime(dt) => new_entry.arrival.adjust_time(*dt),
87 SetArrivalType(nt) => new_entry.arrival = *nt,
88 AdjustDepartureTime(dt) => {
89 new_entry.departure.as_mut().map(|d| d.adjust_time(*dt));
90 }
91 SetDepartureType(nt) => new_entry.departure = *nt,
92 SetStation(ns) => new_entry.station = ns.entity(),
93 SetService(ns) => new_entry.service = *ns,
94 SetTrack(nt) => new_entry.track = *nt,
95 SetNote(note) => {}
96 PassThrough => return,
97 }
98 commands.entity(*entity).insert(new_entry);
99 }
100}