Skip to main content

rosu_replay/
types.rs

1//! Core types and enums for osu! replay data.
2//!
3//! This module defines all the data structures used to represent osu! replay information,
4//! including game modes, mods, key states, and replay events for different game modes.
5
6use serde::{Deserialize, Serialize};
7
8/// Represents the different game modes in osu!
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10pub enum GameMode {
11    /// osu!standard - Traditional circle-clicking mode
12    Std = 0,
13    /// osu!taiko - Drum-based rhythm mode
14    Taiko = 1,
15    /// osu!catch - Fruit-catching mode
16    Catch = 2,
17    /// osu!mania - Piano-style rhythm mode
18    Mania = 3,
19}
20
21impl From<u8> for GameMode {
22    fn from(value: u8) -> Self {
23        match value {
24            0 => GameMode::Std,
25            1 => GameMode::Taiko,
26            2 => GameMode::Catch,
27            3 => GameMode::Mania,
28            _ => GameMode::Std, // Default fallback
29        }
30    }
31}
32
33/// Represents osu! mods as a bitflag integer.
34///
35/// Mods can be combined using bitwise OR operations.
36///
37/// # Example
38///
39/// ```rust
40/// use rosu_replay::Mod;
41///
42/// let hidden_hard_rock = Mod::HIDDEN.0 | Mod::HARD_ROCK.0;
43/// let combined_mod = Mod(hidden_hard_rock);
44/// assert!(combined_mod.contains(Mod::HIDDEN));
45/// assert!(combined_mod.contains(Mod::HARD_ROCK));
46/// ```
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
48pub struct Mod(pub u32);
49
50impl Mod {
51    pub const NO_MOD: Self = Self(0);
52    pub const NO_FAIL: Self = Self(1 << 0);
53    pub const EASY: Self = Self(1 << 1);
54    pub const TOUCH_DEVICE: Self = Self(1 << 2);
55    pub const HIDDEN: Self = Self(1 << 3);
56    pub const HARD_ROCK: Self = Self(1 << 4);
57    pub const SUDDEN_DEATH: Self = Self(1 << 5);
58    pub const DOUBLE_TIME: Self = Self(1 << 6);
59    pub const RELAX: Self = Self(1 << 7);
60    pub const HALF_TIME: Self = Self(1 << 8);
61    pub const NIGHTCORE: Self = Self(1 << 9);
62    pub const FLASHLIGHT: Self = Self(1 << 10);
63    pub const AUTOPLAY: Self = Self(1 << 11);
64    pub const SPUN_OUT: Self = Self(1 << 12);
65    pub const AUTOPILOT: Self = Self(1 << 13);
66    pub const PERFECT: Self = Self(1 << 14);
67    pub const KEY4: Self = Self(1 << 15);
68    pub const KEY5: Self = Self(1 << 16);
69    pub const KEY6: Self = Self(1 << 17);
70    pub const KEY7: Self = Self(1 << 18);
71    pub const KEY8: Self = Self(1 << 19);
72    pub const FADE_IN: Self = Self(1 << 20);
73    pub const RANDOM: Self = Self(1 << 21);
74    pub const CINEMA: Self = Self(1 << 22);
75    pub const TARGET: Self = Self(1 << 23);
76    pub const KEY9: Self = Self(1 << 24);
77    pub const KEY_COOP: Self = Self(1 << 25);
78    pub const KEY1: Self = Self(1 << 26);
79    pub const KEY3: Self = Self(1 << 27);
80    pub const KEY2: Self = Self(1 << 28);
81    pub const SCORE_V2: Self = Self(1 << 29);
82    pub const MIRROR: Self = Self(1 << 30);
83
84    pub fn contains(&self, other: Self) -> bool {
85        (self.0 & other.0) == other.0
86    }
87
88    pub fn value(&self) -> u32 {
89        self.0
90    }
91}
92
93impl From<u32> for Mod {
94    fn from(value: u32) -> Self {
95        Self(value)
96    }
97}
98
99/// Represents keys that can be pressed during osu!standard gameplay.
100/// Includes mouse buttons (M1, M2), keyboard keys (K1, K2), and smoke.
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
102pub struct Key(pub u32);
103
104impl Key {
105    pub const M1: Self = Self(1 << 0);
106    pub const M2: Self = Self(1 << 1);
107    pub const K1: Self = Self(1 << 2);
108    pub const K2: Self = Self(1 << 3);
109    pub const SMOKE: Self = Self(1 << 4);
110
111    pub fn value(&self) -> u32 {
112        self.0
113    }
114}
115
116impl From<u32> for Key {
117    fn from(value: u32) -> Self {
118        Self(value)
119    }
120}
121
122/// Represents keys that can be pressed during osu!taiko gameplay.
123/// Includes different drum hit types for left and right sides.
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
125pub struct KeyTaiko(pub u32);
126
127impl KeyTaiko {
128    pub const LEFT_DON: Self = Self(1 << 0);
129    pub const LEFT_KAT: Self = Self(1 << 1);
130    pub const RIGHT_DON: Self = Self(1 << 2);
131    pub const RIGHT_KAT: Self = Self(1 << 3);
132
133    pub fn value(&self) -> u32 {
134        self.0
135    }
136}
137
138impl From<u32> for KeyTaiko {
139    fn from(value: u32) -> Self {
140        Self(value)
141    }
142}
143
144/// Represents keys that can be pressed during osu!mania gameplay.
145/// Supports up to 18 lanes (K1-K18) for different key configurations.
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
147pub struct KeyMania(pub u32);
148
149impl KeyMania {
150    pub const K1: Self = Self(1 << 0);
151    pub const K2: Self = Self(1 << 1);
152    pub const K3: Self = Self(1 << 2);
153    pub const K4: Self = Self(1 << 3);
154    pub const K5: Self = Self(1 << 4);
155    pub const K6: Self = Self(1 << 5);
156    pub const K7: Self = Self(1 << 6);
157    pub const K8: Self = Self(1 << 7);
158    pub const K9: Self = Self(1 << 8);
159    pub const K10: Self = Self(1 << 9);
160    pub const K11: Self = Self(1 << 10);
161    pub const K12: Self = Self(1 << 11);
162    pub const K13: Self = Self(1 << 12);
163    pub const K14: Self = Self(1 << 13);
164    pub const K15: Self = Self(1 << 14);
165    pub const K16: Self = Self(1 << 15);
166    pub const K17: Self = Self(1 << 16);
167    pub const K18: Self = Self(1 << 17);
168
169    pub fn value(&self) -> u32 {
170        self.0
171    }
172}
173
174impl From<u32> for KeyMania {
175    fn from(value: u32) -> Self {
176        Self(value)
177    }
178}
179
180/// A single event (frame) in a replay, specific to the game mode.
181///
182/// Each variant contains mode-specific information about what happened
183/// at a particular time during the replay.
184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185pub enum ReplayEvent {
186    Osu(ReplayEventOsu),
187    Taiko(ReplayEventTaiko),
188    Catch(ReplayEventCatch),
189    Mania(ReplayEventMania),
190}
191
192impl ReplayEvent {
193    pub fn time_delta(&self) -> i32 {
194        match self {
195            ReplayEvent::Osu(event) => event.time_delta,
196            ReplayEvent::Taiko(event) => event.time_delta,
197            ReplayEvent::Catch(event) => event.time_delta,
198            ReplayEvent::Mania(event) => event.time_delta,
199        }
200    }
201}
202
203#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
204pub struct ReplayEventOsu {
205    pub time_delta: i32,
206    pub x: f32,
207    pub y: f32,
208    pub keys: Key,
209}
210
211#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
212pub struct ReplayEventTaiko {
213    pub time_delta: i32,
214    pub x: i32,
215    pub keys: KeyTaiko,
216}
217
218#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
219pub struct ReplayEventCatch {
220    pub time_delta: i32,
221    pub x: f32,
222    pub dashing: bool,
223}
224
225#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
226pub struct ReplayEventMania {
227    pub time_delta: i32,
228    pub keys: KeyMania,
229}
230
231/// Represents the life bar state at a specific point in time during a replay.
232///
233/// The life bar shows the player's health throughout the song,
234/// typically ranging from 0.0 (empty) to 1.0 (full).
235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
236pub struct LifeBarState {
237    pub time: i32,
238    pub life: f32,
239}