Skip to main content

rosu_pp/osu/performance/
inspect.rs

1use std::cmp;
2
3use crate::{
4    Difficulty,
5    any::{HitResultPriority, InspectablePerformance},
6    osu::{Osu, OsuDifficultyAttributes, OsuScoreOrigin},
7};
8
9/// Inspectable [`OsuPerformance`] to expose all of its internal details.
10///
11/// [`OsuPerformance`]: crate::osu::performance::OsuPerformance
12#[derive(Clone, Debug)]
13pub struct InspectOsuPerformance<'a> {
14    pub attrs: &'a OsuDifficultyAttributes,
15    pub difficulty: &'a Difficulty,
16    pub acc: Option<f64>,
17    pub combo: Option<u32>,
18    pub large_tick_hits: Option<u32>,
19    pub small_tick_hits: Option<u32>,
20    pub slider_end_hits: Option<u32>,
21    pub n300: Option<u32>,
22    pub n100: Option<u32>,
23    pub n50: Option<u32>,
24    pub misses: Option<u32>,
25    pub hitresult_priority: HitResultPriority,
26}
27
28impl InspectOsuPerformance<'_> {
29    pub fn total_hits(&self) -> u32 {
30        cmp::min(
31            self.difficulty.get_passed_objects() as u32,
32            self.attrs.n_objects(),
33        )
34    }
35
36    pub fn misses(&self) -> u32 {
37        self.misses.map_or(0, |n| cmp::min(n, self.total_hits()))
38    }
39
40    pub fn lazer(&self) -> bool {
41        self.difficulty.get_lazer()
42    }
43
44    pub fn using_classic_slider_acc(&self) -> bool {
45        self.difficulty.get_mods().no_slider_head_acc(self.lazer())
46    }
47
48    pub fn origin(&self) -> OsuScoreOrigin {
49        match (self.lazer(), self.using_classic_slider_acc()) {
50            (false, _) => OsuScoreOrigin::Stable,
51            (true, false) => OsuScoreOrigin::WithSliderAcc {
52                max_large_ticks: self.attrs.n_large_ticks,
53                max_slider_ends: self.attrs.n_sliders,
54            },
55            (true, true) => OsuScoreOrigin::WithoutSliderAcc {
56                max_large_ticks: self.attrs.n_sliders + self.attrs.n_large_ticks,
57                max_small_ticks: self.attrs.n_sliders,
58            },
59        }
60    }
61
62    /// Returns the number of slider end hits, large tick hits, and small tick
63    /// hits.
64    pub fn tick_hits(&self) -> (u32, u32, u32) {
65        let lazer = self.lazer();
66        let using_classic_slider_acc = self.using_classic_slider_acc();
67
68        match (lazer, using_classic_slider_acc) {
69            (false, _) => (0, 0, 0),
70            (true, false) => {
71                let slider_end_hits = self
72                    .slider_end_hits
73                    .map_or(self.attrs.n_sliders, |n| cmp::min(n, self.attrs.n_sliders));
74
75                let large_tick_hits = self.large_tick_hits.map_or(self.attrs.n_large_ticks, |n| {
76                    cmp::min(n, self.attrs.n_large_ticks)
77                });
78
79                (slider_end_hits, large_tick_hits, 0)
80            }
81            (true, true) => {
82                let small_tick_hits = self
83                    .small_tick_hits
84                    .map_or(self.attrs.n_sliders, |n| cmp::min(n, self.attrs.n_sliders));
85
86                let large_tick_hits = self
87                    .large_tick_hits
88                    .map_or(self.attrs.n_sliders + self.attrs.n_large_ticks, |n| {
89                        cmp::min(n, self.attrs.n_sliders + self.attrs.n_large_ticks)
90                    });
91
92                (0, large_tick_hits, small_tick_hits)
93            }
94        }
95    }
96}
97
98impl InspectablePerformance for Osu {
99    type InspectPerformance<'a> = InspectOsuPerformance<'a>;
100
101    fn inspect_performance<'a>(
102        perf: &'a Self::Performance<'_>,
103        attrs: &'a Self::DifficultyAttributes,
104    ) -> Self::InspectPerformance<'a> {
105        InspectOsuPerformance {
106            attrs,
107            difficulty: &perf.difficulty,
108            acc: perf.acc,
109            combo: perf.combo,
110            large_tick_hits: perf.large_tick_hits,
111            small_tick_hits: perf.small_tick_hits,
112            slider_end_hits: perf.slider_end_hits,
113            n300: perf.n300,
114            n100: perf.n100,
115            n50: perf.n50,
116            misses: perf.misses,
117            hitresult_priority: perf.hitresult_priority,
118        }
119    }
120}