rosu_pp/osu/performance/
inspect.rs1use std::cmp;
2
3use crate::{
4 Difficulty,
5 any::{HitResultPriority, InspectablePerformance},
6 osu::{Osu, OsuDifficultyAttributes, OsuScoreOrigin},
7};
8
9#[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 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}