rosu_pp/model/
hit_object.rs

1use std::cmp::Ordering;
2
3use rosu_map::section::{
4    general::GameMode,
5    hit_objects::{BorrowedCurve, CurveBuffers},
6};
7
8pub use rosu_map::{
9    section::hit_objects::{hit_samples::HitSoundType, PathControlPoint, PathType, SplineType},
10    util::Pos,
11};
12
13/// All hitobject related data required for difficulty and performance
14/// calculation except for the [`HitSoundType`].
15#[derive(Clone, Debug, PartialEq)]
16pub struct HitObject {
17    pub pos: Pos,
18    pub start_time: f64,
19    pub kind: HitObjectKind,
20}
21
22impl HitObject {
23    /// Whether the hitobject is a circle.
24    pub const fn is_circle(&self) -> bool {
25        matches!(&self.kind, HitObjectKind::Circle)
26    }
27
28    /// Whether the hitobject is a slider.
29    pub const fn is_slider(&self) -> bool {
30        matches!(&self.kind, HitObjectKind::Slider(_))
31    }
32
33    /// Whether the hitobject is a spinner.
34    pub const fn is_spinner(&self) -> bool {
35        matches!(&self.kind, HitObjectKind::Spinner(_))
36    }
37
38    /// Whether the hitobject is a hold note.
39    pub const fn is_hold_note(&self) -> bool {
40        matches!(&self.kind, HitObjectKind::Hold(_))
41    }
42
43    /// The end time of the object.
44    ///
45    /// Note that this will not return the correct value for sliders.
46    pub(crate) fn end_time(&self) -> f64 {
47        match &self.kind {
48            HitObjectKind::Circle | HitObjectKind::Slider { .. } => self.start_time,
49            HitObjectKind::Spinner(Spinner { duration })
50            | HitObjectKind::Hold(HoldNote { duration }) => self.start_time + *duration,
51        }
52    }
53}
54
55impl PartialOrd for HitObject {
56    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
57        self.start_time.partial_cmp(&other.start_time)
58    }
59}
60
61/// Additional data for a [`HitObject`].
62///
63/// Note that each mode handles hit objects differently.
64#[derive(Clone, Debug, PartialEq)]
65pub enum HitObjectKind {
66    Circle,
67    Slider(Slider),
68    Spinner(Spinner),
69    Hold(HoldNote),
70}
71
72/// A slider.
73#[derive(Clone, Debug, PartialEq)]
74pub struct Slider {
75    pub expected_dist: Option<f64>,
76    pub repeats: usize,
77    pub control_points: Box<[PathControlPoint]>,
78    pub node_sounds: Box<[HitSoundType]>,
79}
80
81impl Slider {
82    /// The amount of spans of the slider.
83    pub const fn span_count(&self) -> usize {
84        self.repeats + 1
85    }
86
87    pub(crate) fn curve<'a>(
88        &self,
89        mode: GameMode,
90        bufs: &'a mut CurveBuffers,
91    ) -> BorrowedCurve<'a> {
92        BorrowedCurve::new(mode, &self.control_points, self.expected_dist, bufs)
93    }
94}
95
96/// A spinner.
97#[derive(Copy, Clone, Debug, PartialEq)]
98pub struct Spinner {
99    pub duration: f64,
100}
101
102/// A hold note.
103#[derive(Copy, Clone, Debug, PartialEq)]
104pub struct HoldNote {
105    pub duration: f64,
106}