Skip to main content

elevator_core/components/
rider.rs

1//! Rider (passenger/cargo) core data and lifecycle.
2
3use serde::{Deserialize, Serialize};
4
5use crate::entity::EntityId;
6
7/// Lifecycle phase of a rider entity.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[non_exhaustive]
10pub enum RiderPhase {
11    /// Waiting at a stop.
12    Waiting,
13    /// Boarding an elevator (transient, one tick).
14    Boarding(EntityId),
15    /// Riding in an elevator.
16    Riding(EntityId),
17    /// Exiting an elevator (transient, one tick).
18    #[serde(alias = "Alighting")]
19    Exiting(EntityId),
20    /// Walking between transfer stops.
21    Walking,
22    /// Reached final destination.
23    Arrived,
24    /// Gave up waiting.
25    Abandoned,
26    /// Parked at a stop, not seeking an elevator.
27    Resident,
28}
29
30impl std::fmt::Display for RiderPhase {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        match self {
33            Self::Waiting => write!(f, "Waiting"),
34            Self::Boarding(id) => write!(f, "Boarding({id:?})"),
35            Self::Riding(id) => write!(f, "Riding({id:?})"),
36            Self::Exiting(id) => write!(f, "Exiting({id:?})"),
37            Self::Walking => write!(f, "Walking"),
38            Self::Arrived => write!(f, "Arrived"),
39            Self::Abandoned => write!(f, "Abandoned"),
40            Self::Resident => write!(f, "Resident"),
41        }
42    }
43}
44
45/// Core component for any entity that rides elevators.
46///
47/// This is the minimum data the simulation needs. Games attach
48/// additional components (`VipTag`, `FreightData`, `PersonData`, etc.)
49/// for game-specific behavior. An entity with `Rider` but no
50/// Route component can be boarded/exited manually by game code.
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct Rider {
53    /// Weight contributed to elevator load.
54    pub(crate) weight: f64,
55    /// Current rider lifecycle phase.
56    pub(crate) phase: RiderPhase,
57    /// The stop entity this rider is currently at (while Waiting/Arrived/Abandoned/Resident).
58    pub(crate) current_stop: Option<EntityId>,
59    /// Tick when this rider was spawned.
60    pub(crate) spawn_tick: u64,
61    /// Tick when this rider boarded (for ride-time metrics).
62    pub(crate) board_tick: Option<u64>,
63}
64
65impl Rider {
66    /// Weight contributed to elevator load.
67    #[must_use]
68    pub const fn weight(&self) -> f64 {
69        self.weight
70    }
71
72    /// Current rider lifecycle phase.
73    #[must_use]
74    pub const fn phase(&self) -> RiderPhase {
75        self.phase
76    }
77
78    /// The stop entity this rider is currently at (while Waiting/Arrived/Abandoned/Resident).
79    #[must_use]
80    pub const fn current_stop(&self) -> Option<EntityId> {
81        self.current_stop
82    }
83
84    /// Tick when this rider was spawned.
85    #[must_use]
86    pub const fn spawn_tick(&self) -> u64 {
87        self.spawn_tick
88    }
89
90    /// Tick when this rider boarded (for ride-time metrics).
91    #[must_use]
92    pub const fn board_tick(&self) -> Option<u64> {
93        self.board_tick
94    }
95}