Skip to main content

rkg_utils/input_data/
face_input.rs

1/// Errors that can occur while parsing a [`FaceButton`] combination.
2#[derive(thiserror::Error, Debug)]
3pub enum FaceButtonError {
4    /// The face button byte was non-zero but did not match any known button bit.
5    #[error("Non Existent Face Button")]
6    NonExistentFaceButton,
7}
8
9/// A face button that can be active during a single input entry.
10///
11/// Multiple buttons may be simultaneously active in a single [`FaceInput`];
12/// see [`parse_face_buttons`] for the bitmask layout.
13#[derive(Clone, Copy, Debug, PartialEq)]
14pub enum FaceButton {
15    /// Accelerator button (bit 0, mask `0x01`).
16    Accelerator,
17    /// Brake button (bit 1, mask `0x02`).
18    Brake,
19    /// Drift button (bit 3, mask `0x08`).
20    Drift,
21    /// Combined brake and drift (bit 4, mask `0x10`).
22    BrakeDrift,
23    /// Item button (bit 2, mask `0x04`).
24    Item,
25    /// An unrecognized button bit was set in the upper nibble.
26    Unknown,
27}
28
29/// Parses all active [`FaceButton`]s from a packed face-button byte.
30///
31/// Each bit in the byte corresponds to one or more buttons. Bit 6 (`0x40`) is
32/// reserved for the CTGP pause flag and is ignored here. If the upper nibble
33/// has any bits set (excluding bit 6) a [`FaceButton::Unknown`] entry is
34/// appended to signal unrecognized input.
35///
36/// # Errors
37///
38/// Returns [`FaceButtonError::NonExistentFaceButton`] if the byte is non-zero,
39/// bit 6 is not set, and no known button bits were matched.
40pub fn parse_face_buttons(value: u8) -> Result<Vec<FaceButton>, FaceButtonError> {
41    let mut buttons = Vec::new();
42
43    if value & 0x01 != 0 {
44        buttons.push(FaceButton::Accelerator);
45    }
46
47    if value & 0x02 != 0 {
48        buttons.push(FaceButton::Brake);
49    }
50
51    if value & 0x08 != 0 {
52        buttons.push(FaceButton::Drift);
53    }
54
55    if value & 0x10 != 0 {
56        buttons.push(FaceButton::BrakeDrift);
57    }
58
59    if value & 0x04 != 0 {
60        buttons.push(FaceButton::Item);
61    }
62
63    // 0x40 is the CTGP pause mask and would trigger this otherwise
64    if value & 0xF0 != 0 && value & 0x40 == 0 {
65        buttons.push(FaceButton::Unknown);
66    }
67
68    if value != 0x00 && value & 0x40 == 0 && buttons.is_empty() {
69        return Err(FaceButtonError::NonExistentFaceButton);
70    }
71
72    Ok(buttons)
73}
74
75/// Errors that can occur while parsing a [`FaceInput`].
76#[derive(thiserror::Error, Debug)]
77pub enum FaceInputError {
78    /// The raw bytes did not form a valid face input entry.
79    #[error("Invalid Face Input")]
80    InvalidFaceInput,
81    /// The face button byte could not be parsed.
82    #[error("Invalid Face Button: {0}")]
83    InvalidButton(#[from] FaceButtonError),
84}
85
86/// A single encoded face-button input entry from a Mario Kart Wii ghost file.
87///
88/// Each entry records which face buttons were held and for how many consecutive
89/// frames they were held. Unlike D-pad inputs, the frame duration is stored as
90/// a single byte and does not support multi-byte encoding.
91#[derive(Debug)]
92pub struct FaceInput {
93    /// The set of face buttons active during this input entry.
94    buttons: Vec<FaceButton>,
95    /// The number of frames this button state was held.
96    frame_duration: u32,
97}
98
99impl FaceInput {
100    /// Returns the set of face buttons active during this input entry.
101    pub fn buttons(&self) -> &Vec<FaceButton> {
102        &self.buttons
103    }
104
105    /// Returns the number of frames this button state was held.
106    pub fn frame_duration(&self) -> u32 {
107        self.frame_duration
108    }
109
110    /// Sets the number of frames this button state was held.
111    pub fn set_frame_duration(&mut self, frame_duration: u32) {
112        self.frame_duration = frame_duration;
113    }
114}
115
116/// Two [`FaceInput`] values are equal if they share the same set of active
117/// buttons, regardless of frame duration.
118impl PartialEq for FaceInput {
119    fn eq(&self, other: &Self) -> bool {
120        self.buttons == other.buttons
121    }
122}
123
124/// Parses a [`FaceInput`] from a 2-byte slice.
125///
126/// # Errors
127///
128/// Returns [`FaceInputError::InvalidButton`] if the button byte does not map
129/// to any known face button combination.
130impl TryFrom<&[u8]> for FaceInput {
131    type Error = FaceInputError;
132
133    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
134        let buttons = parse_face_buttons(value[0])?;
135        let frame_duration = value[1] as u32;
136
137        Ok(Self {
138            buttons,
139            frame_duration,
140        })
141    }
142}