1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! Library to calculate difficulty and performance attributes for all [osu!] gamemodes.
//!
//! A large part of `rosu-pp` is a port of [osu!lazer]'s difficulty and performance calculation
//! with emphasis on a precise translation to Rust for the most [accurate results](#accuracy)
//! while also providing a significant [boost in performance](#speed).
//!
//! Last commits of the ported code:
//! - [osu!lazer] : `28c846b4d9366484792e27f4729cd1afa2cdeb66` (2025-10-13)
//! - [osu!tools] : `ab97b64f60901952926b2121ddffb8976d7f8775` (2025-10-16)
//!
//! News posts of the latest updates: <https://osu.ppy.sh/home/news/2025-10-29-performance-points-star-rating-updates>
//!
//! ## Usage
//!
//! ```
//! // Decode the map
//! let map = rosu_pp::Beatmap::from_path("./resources/2785319.osu").unwrap();
//!
//! // Whereas osu! simply times out on malicious maps, rosu-pp does not. To
//! // prevent potential performance/memory issues, it is recommended to check
//! // beforehand whether a map is too suspicious for further calculation.
//! // Alternatively, using e.g. `checked_calculate` instead of `calculate`
//! // performs the same suspicion check before calculating.
//! if let Err(sus) = map.check_suspicion() {
//! panic!("{sus:?}");
//! }
//!
//! // Calculate difficulty attributes
//! let diff_attrs = rosu_pp::Difficulty::new()
//! .mods(8 + 16) // HDHR
//! .calculate(&map); // or `checked_calculate`
//!
//! let stars = diff_attrs.stars();
//!
//! // Calculate performance attributes
//! let perf_attrs = rosu_pp::Performance::new(diff_attrs)
//! // To speed up the calculation, we used the previous attributes.
//! // **Note** that this should only be done if the map and all difficulty
//! // settings stay the same, otherwise the final attributes will be incorrect!
//! .mods(24) // HDHR, must be the same as before
//! .combo(789)
//! .accuracy(99.2)
//! .misses(2)
//! .calculate();
//!
//! let pp = perf_attrs.pp();
//!
//! // Again, we re-use the previous attributes for maximum efficiency.
//! let max_pp = perf_attrs.performance()
//! .mods(24) // Still the same
//! .calculate()
//! .pp();
//!
//! println!("Stars: {stars} | PP: {pp}/{max_pp}");
//! ```
//!
//! ## Gradual calculation
//!
//! Gradually calculating attributes provides an efficient way to process each hitobject
//! separately and calculate the attributes only up to that point.
//!
//! For difficulty attributes, there is [`GradualDifficulty`] which implements `Iterator`
//! and for performance attributes there is [`GradualPerformance`] which requires the current
//! score state.
//!
//! ```
//! use rosu_pp::{Beatmap, GradualPerformance, Difficulty, any::ScoreState};
//!
//! let map = Beatmap::from_path("./resources/1028484.osu").unwrap();
//!
//! let mut gradual = Difficulty::new()
//! .mods(16 + 64) // HRDT
//! .clock_rate(1.2)
//! .gradual_performance(&map);
//!
//! let mut state = ScoreState::new(); // empty state, everything is on 0.
//!
//! // The first 10 hitresults are 300s
//! for _ in 0..10 {
//! state.n300 += 1;
//! state.max_combo += 1;
//! let attrs = gradual.next(state.clone()).unwrap();
//! println!("PP: {}", attrs.pp());
//! }
//!
//! // Fast-forward to the end
//! # /*
//! state.max_combo = ...
//! state.n300 = ...
//! state.n_katu = ...
//! ...
//! # */
//! let attrs = gradual.last(state).unwrap();
//! println!("PP: {}", attrs.pp());
//! ```
//!
//! ## Accuracy
//!
//! `rosu-pp` was tested against millions of real scores and delivered
//! values that matched osu!lazer perfectly down to the last decimal place.
//!
//! However, there is one small caveat: the values are only this precise on debug mode.
//! On release mode, Rust's compiler performs optimizations that produce the tiniest discrepancies
//! due to floating point inaccuracies. With this in mind, `rosu-pp` is still as accurate as can
//! be without targeting the .NET compiler itself.
//! Realistically, the inaccuracies in release mode are negligibly small.
//!
//! ## Speed
//!
//! An important factor for `rosu-pp` is the calculation speed. Optimizations and an accurate translation
//! unfortunately don't always go hand-in-hand. Nonetheless, performance improvements are still
//! snuck in wherever possible, providing a significantly faster runtime than the native C# code.
//!
//! Results of a rudimentary [benchmark] of osu!lazer and rosu-pp:
//! ```txt
//! osu!lazer:
//! Decoding maps: Median: 325.18ms | Mean: 325.50ms
//! Calculating difficulties: Median: 568.63ms | Mean: 575.97ms
//! Calculating performances: Median: 256.00µs | Mean: 240.40µs
//!
//! rosu-pp:
//! Decoding maps: Median: 46.03ms | Mean: 47.13ms
//! Calculating difficulties: Median: 82.11ms | Mean: 84.27ms
//! Calculating performances: Median: 40.57µs | Mean: 43.41µs
//! ```
//!
//! ## Features
//!
//! | Flag | Description | Dependencies
//! | ------------- | ------------------- | ------------
//! | `default` | No features enabled |
//! | `sync` | Some gradual calculation types can only be shared across threads if this feature is enabled. This feature adds a small performance penalty. |
//! | `tracing` | Any error encountered during beatmap decoding will be logged through `tracing::error`. If this feature is **not** enabled, errors will be ignored. | [`tracing`]
//!
//! ## Bindings
//!
//! Using `rosu-pp` from other languages than Rust:
//! - JavaScript: [rosu-pp-js]
//! - Python: [rosu-pp-py]
//!
//! [osu!]: https://osu.ppy.sh/home
//! [osu!lazer]: https://github.com/ppy/osu
//! [osu!tools]: https://github.com/ppy/osu-tools
//! [`tracing`]: https://docs.rs/tracing
//! [rosu-pp-js]: https://github.com/MaxOhn/rosu-pp-js
//! [rosu-pp-py]: https://github.com/MaxOhn/rosu-pp-py
//! [benchmark]: https://gist.github.com/MaxOhn/625af10011f6d7e13a171b08ccf959ff
//! [`GradualDifficulty`]: crate::any::GradualDifficulty
//! [`GradualPerformance`]: crate::any::GradualPerformance
pub use ;
/// Types for calculations of any mode.
/// Types for osu!standard calculations.
/// Types for osu!taiko calculations.
/// Types for osu!catch calculations.
/// Types for osu!mania calculations.
/// Types used in and around this crate.