The rosu-pp
interface and internal structure has been rewritten completely. Fields have been
modified, builders work differently, function arguments have changed, and some types are no longer
exposed.
Additionally, osu!catch has finally been updated to match osu!lazer as closely as possible, just like the other modes already did.
- Beatmap converts
- Each mode now has a ZST, i.e.
Osu
,Taiko
,Catch
, andMania
, which are used to specify a mode at compile-time. Most of their utility comes from the newIGameMode
trait. - Each mode's calculators now require
Converted
beatmaps to make sure they're valid for the mode, e.g. theTaikoPerformance
calculator no longer takes a simpleBeatmap
but aConverted<'_, Taiko>
(or its aliasTaikoBeatmap<'_>
). - Conversion between
Beatmap
andConverted<'_, M>
either- is essentially a free operation if the map's mode already matches
M
, - or performs the required conversion by modifying hitobjects & co,
- or indicates an error due to incompatible mode conversion, e.g. a mania map cannot be converted to a taiko map
- is essentially a free operation if the map's mode already matches
- Each mode now has a ZST, i.e.
- Difficulty calculation
- The
Difficulty
type is the core of all difficulty calculations and acts as a builder to specify various parameters. - To calculate values for a specific mode, the method
Difficulty::with_mode
will produce a builder to calculate values for that mode. - Recycled attributes are only valid if all difficulty parameters match, i.e. it must be on the same map, use the same mods, clock rate, custom beatmap attributes, and passed object count (and hardrock offset for osu!catch).
- Clockrate is now always clamped between 0.01 and 100 and custom beatmap attributes are clamped between -20 and 20.
- The
- Performance calculation
- Each mode's performance calculator was renamed from
[Mode]PP
to[Mode]Performance
andAnyPP
is now calledPerformance
. - Difficulty attributes now contain a few more values so that the beatmap is no longer necessary for performance calculation as long as difficulty attributes are available.
- The functions
[Mode]Performance::new
now take an argument implementing the traitInto(Mode)Performance
, i.e. either a beatmap (as before), or attributes (difficulty or performance). Since attributes speed up the calculation, they should be prefered whenever available. However, be mindful that they have been calculated for the same map and difficulty settings. Otherwise, the final attributes will be incorrect.
- Each mode's performance calculator was renamed from
- Features
- The
tracing
feature has been added. Its sole functionality is that errors during beatmap parsing will emit atracing
event on theERROR
level. If this features is not explicitely enabled, parsing errors will be ignored entirely. - The
gradual
features has been removed. Types for gradual calculation are now always available. - The
sync
feature has been added. Taiko's gradual calculation types contain types that are not thread-safe by default. Enabling this feature will add some performance penalty but use types that do allow moving gradual calculation across threads. - The
compact_strains
feature is now enabled by default and causes strain values during difficulty calculation to be stored in a space-efficient way to prevent out-of-memory issues on maliciously long maps. This comes at a small performance cost.
- The
- Misc
- Async is no longer supported. Beatmap parsing now works through rosu-map which does not support async since evidently it's generally slower than regular sequential code.
- Errors while parsing a beatmap will never be propagated. The only errors that will be
propagated are those occuring while decoding, e.g. a file couldn't be read or other IO errors.
Notably, this means that some content is now parsed successfully into a
Beatmap
whereas in previousrosu-pp
versions it would error, e.g. an empty file is now a validBeatmap
. - Although new lazer mods such as
DifficultyAdjust
orDoubleTime
with a custom clockrate are essentially supported by providing methods to specify their parameters, mods themselves are still specified by their bit value. This means:Daycore
will not be considered unless its clockrate change is explicitly specified- /!\
Blinds
will not be considered for osu! performance calculation /!\
- Most
usize
types are nowu32
, e.g. fields ofScoreState
ormax_combo
in attributes. n_misses
has generally been renamed tomisses
for both fields and methods.- Types such as
NestedObjectKind
,ManiaObject
, orMods
that were only used for internal calculations are no longer publicly exposed.
Essentially only adjustments to the API so bindings won't need an update.
-
Additions:
- Added
From<u8>
impl forGameMode
- Added the method
AnyPP::hitresult_priority
- Added the method
[Mode]PP::generate_state
which returns the score state that will be used for performance calculation (#23) - The struct
SortedVec
has now an improved public interface so it can be constructed and pushed onto (#22)
- Added
-
Breaking adjustments:
- Removed the method
HitObject::end_time
from the public api. (#25) - The fields
control_points
andedge_sounds
ofHitObjectKind::Slider
are now stored in aBox
rather than aVec
. (#26) - Overhauled gradual calculation. All relevant types are now gated behind the
gradual
feature which must be enabled. (#24) *GradualDifficultyAttributes
has been renamed to*GradualDifficulty
and*GradualPerformanceAttributes
has been renamed to*GradualPerformance
.- Types for gradual calculation that depend on a lifetime now have a counterpart without a lifetime that might clone
underlying data along the way. E.g. now there is
CatchOwnedGradualDifficulty
and[Mode]OwnedGradualPerformance
. OsuGradualDifficulty
and thusGradualDifficulty
no longer implementClone
.- Gradual performance calculators' method
process_next_object
has been renamed tonext
andprocess_next_n_objects
has been renamed tonth
. They now also have the new methodlast
. - Similar to
Iterator::nth
, gradual performance calculators' methodnth
is now zero-indexed i.e. passingn=0
will process 1 object,n=1
will process 2, and so on.
- Removed the method
-
Additions:
- Added the method
{AnyStars/AnyPP}::is_convert
which needs to be used if the map was manually converted beforehand
- Added the method
-
Adjustments:
- Specified clock rates can go below 0.001 again
-
Fixes:
- Fixed underflow for osu!std scores that were FCs but quit mid-slider
- Fixed panic on incorrect file headers (#21)
-
Additions:
- Added the method
{TaikoPP/ManiaPP}::is_convert
which needs to be used if the map was manually converted beforehand
- Added the method
-
Adjustments:
- Specified clock rates can no longer go below 0.001 to prevent crashing due to memory hogging.
- (technically breaking) The only reasons for parsing to fail are now IO errors or invalid file headers. All other
ParseError
variants have been removed and instead of throwing an error the line is just ignored.
-
Fixes:
- The
Beatmap::bpm
method now works properly by considering the most common beat length instead of just the first one
- The
-
Additions:
- Added the method
ScoreState::total_hits
- Added the trait methods
BeatmapExt::{mode}_hitobjects
which return a list of mode-specific processedHitObject
s (#20)
- Added the method
-
Fixes:
- Lines with invalid curve points are now ignored instead of throwing an error while parsing
- Fixed a niche capacity overflow in curve generation
-
Adjustments:
- When passing an osu!std map to
TaikoGradualDifficultyAttributes
orManiaGradualDifficultyAttributes
, it now automatically converts the map internally. For osu!catch it was already happening trivially.
- When passing an osu!std map to
-
Fixes:
- Fixed passed object count for taiko by ignoring non-circles
- Fixed a niche panic on UTF-16 encoded maps (#18)
- Fixed an occasional underflow when calculating accuracy pp
- Fixed an infinite loop on special ctb maps
-
Adjustments:
- When passing an osu!std map to
TaikoPP
orManiaPP
, it now automatically converts the map internally. For osu!catch it was already happening trivially.
- When passing an osu!std map to
-
Fixes:
- The fields
section_len
for all strain structs no longer depends on the clock rate.
- The fields
Big changes including the most recent osu!, taiko, and mania updates, aswell as various breaking changes.
-
Breaking changes:
TimingPoint
andDifficultyPoint
no longer contain akiai
fieldDifficultyPoint
now has the additional fieldsbpm_mult
andgenerate_ticks
Beatmap
now stores timing- and difficulty points in aSortedVec
Beatmap
now has the additional fieldeffect_points
- For the performance calculators
OsuPP
,TaikoPP
,ManiaPP
, andAnyPP
the methodmisses
has been renamed ton_misses
- The accuracy method for
OsuPP
,TaikoPP
, andManiaPP
is no longer required to be called last ManiaPP
no longer has ascore
method. Instead it hasn320
,n300
.n200
,n100
,n50
, andn_misses
methods, aswell as astate
method- Gradual performance calculation for mania now requires a
ManiaScoreState
instead ofscore
ManiaDifficultyAttributes
now have amax_combo
field and methodOsuDifficultyAttributes
now have aspeed_note_count
fieldOsuPerformanceAttributes
andTaikoPerformanceAttributes
now have aeffective_miss_count
fieldTaikoDifficultyAttributes
now have apeak
andhit_window
field- Some other things I likely forgot about :S
-
Additions:
- The performance calculators
OsuPP
,TaikoPP
,ManiaPP
, andAnyPP
now have ahitresult_priority
method to specify how hitresults should be generated
- The performance calculators
-
Fixes:
- Fixed a bunch of fringe yet significant bugs for taiko and mania converts
- Fixed various floating point inaccuracies for osu!standard
- Fixed parsing difficulty points from .osu files
- Instead of throwing an error, invalid lines during parsing will just be ignored in some cases
- Fixed an unsafe transmute between incompatible types while parsing sliders
- Fixes:
- Fixed stack overflow bug when allocating ticks for some sliders on converted catch maps (#14)
- Breaking changes:
Beatmap::attributes
now returns a new typeBeatmapAttributesBuilder
to allow for more fine-grained calculations.BeatmapAttributes
now contains expected values and also includes aBeatmapHitWindows
field containing the AR (preempt) and OD (great) hit windows in milliseconds. (#15)
- Fixes:
- Parsing edge sounds is now mindful about overflowing a byte (ref. ranked map id 80799)
- Parsing the event section now attempts to read non-ASCII before eventually failing (ref. ranked map id 49374)
- Fixes:
- Slider velocity is now adjusted properly for taiko converts
- Fixed missing slider sounds for taiko converts
- Breaking changes:
- Replaced the simple
Strains
struct with a new struct{Mode}Strains
that contains more detail w.r.t. the mode. - Renamed all
GameMode
variants to more idiomatic names - Renamed
ParseError::IOError
toParseError::IoError
- Replaced the simple
- Additions:
- Added the
ControlPoint
andControlPointerIter
types to the public interface TimingPoint
andDifficultyPoint
now implementDefault
- Added new methods to
Beatmap
:convert_mode
: Convert a map into another mode. (doesn't do anything if the starting map is not osu!standard)control_points
: Return an iterator over all control points of a maptotal_break_time
: Return the accumulated break time in millisecondstiming_point_at
: Return the timing point for the given timestampdifficulty_point_at
: Return the difficulty point for the given timestamp if available
- Added the
- Breaking changes:
- Moved some types to a different module. The following types can now be found in
rosu_pp::beatmap
:Beatmap
BeatmapAttributes
ControlPoint
ControlPointIter
DifficultyPoint
GameMode
TimingPoint
- Added a new field
kiai: bool
to bothTimingPoint
andDifficultyPoint
to denote whether the current timing section is in kiai mode - Added a new field
breaks: Vec<Break>
toBeatmap
that contains all breaks throughout the map - Added a new field
edge_sounds: Vec<u8>
to theSlider
variant ofHitObjectKind
to denote the sample played on slider heads, ends, and repeats
- Moved some types to a different module. The following types can now be found in
- Other:
- Small performance improvements for osu!taiko calculations
- Fixes:
- Fixed parsing non-UTF-8 encoded files and improved parse performance overall (#9)
- Handle missing approach rate properly this time
- Fixes:
- Performance calculation for taiko & mania now considers custom clock rates properly
- Fixes:
- Fixed panic on maps with 0 objects
- Fixed droplet timings on juicestreams with span count >1
- Fixed timing point parsing on some (older) maps where "uninherited" value did not coincide with beat length
- Fixed handling .osu files with missing difficulty attributes
- Fixed huge memory allocations caused by incorrectly parsing .osu files
- Breaking changes:
- The
stars
andstrains
functions for all modes were removed. Instead use the{Mode}Stars
builder pattern which is similar to{Mode}PP
. BeatmapExt::stars
's definition was adjusted to use theAnyStars
builder struct- Store
HitObject::sound
inBeatmap::sounds
instead to reduce the struct size - Removed the mode features
osu
,fruits
,taiko
, andmania
. Now all modes are always supported. - Renamed the
rosu_pp::fruits
module torosu_pp::catch
. Similarly, all structsFruits{Name}
were renamed toCatch{Name}
and enums over the mode have theirFruits
variant renamed toCatch
- Renamed
Mods
' methodspeed
toclock_rate
- The
- Additions:
- Added
AttributeProvider
impl for{Mode}PerformanceAttributes
- Added the method
clock_rate
to{Mode}PP
and{Mode}Stars
to consider a custom clock rate instead of the one dictated by mods.
- Added
- Fixed out of bounds panic on maps with single-control-point linear sliders
- Fixed incorrect attributes on maps with only 1 or 2 hit objects for all modes
- Added method
Beatmap::from_path
so the file does not have to be created manually forBeatmap::parse
. - Added a bunch of documentation.
- Added method
Beatmap::bpm
- Added method
max_combo
forDifficultyAttributes
,PerformanceAttributes
, and all{Mode}PerformanceAttributes
- Added methods
TaikoDifficultyAttributes::max_combo
andOsuDifficultyAttributes::max_combo
- Added structs
{Mode}GradualDifficultyAttributes
to calculate a map's difficulty after every or every few objects instead of calling the mode'sstars
function over and over. - Added structs
{Mode}GradualPerformanceAttributes
to calculate the performance on a map after every or every few objects instead of using{Mode}PP
over and over. - Added
BeatmapExt::gradual_difficulty
andBeatmapExt::gradual_performance
to gradually calculate the difficulty or performance on maps of any mode, hit object by hit object. - Added methods
{Mode}PP::state
that take a{Mode}ScoreState
(same forAnyPP
andScoreState
) to set all parameters at once. - [BREAKING] Removed the
ParseError
variantsInvalidPathType
andInvalidTimingSignature
and renamedInvalidFloatingPoint
toInvalidDecimalNumber
. - [BREAKING] Removed the
last_control_point
field ofHitObjectKind::Slider
when neither theosu
nor thefruits
feature is enabled. - [BREAKING] Added the field
TaikoDifficultyAttributes::max_combo
- [BREAKING] Renamed the
attributes
field todifficulty
for all{Mode}PerformanceAttributes
structs - [BREAKING] Replaced field
FruitsDifficultyAttributes::max_combo
by a method with the same name
- [BREAKING] With the importance of sliders for osu!standard, the
no_sliders_no_leniency
feature became too inaccurate. Additionally, since considering sliders now inherently drags performance down a little more, the difference betweenno_leniency
andall_included
became too small. Hence, the three osu featuresno_sliders_no_leniency
,no_leniency
, andall_included
were removed. When theosu
feature is enabled, it will now essentially useall_included
under the hood. Additionally, instead of importing throughrosu_pp::osu::{version}
, you now have to import throughrosu_pp::osu
. - [BREAKING] Instead of returning
PpResult
, performance calculations now return{Mode}PerformanceAttributes
andPpResult
has been renamed toPerformanceAttributes
. - [BREAKING] Instead of returning
StarResult
, difficulty calculations now return{Mode}DifficultyAttributes
andStarResult
has been renamed toDifficultyAttributes
. - [BREAKING] Various fields and methods now include
f64
instead off32
to stay true to osu!'s original code - Added internal binary crate
pp-gen
to calculate difficulty & pp values viaPerformanceCalculator.dll
- Added internal binary crate
pp-plot
to plot out differences betweenpp-gen
's output androsu-pp
values - osu: Updated up to commit 9fb2402781ad91c197d51aeec716b0000f52c4d1 (2021-11-12)
- Reduced amount of required features of
async_std
andasync_tokio
- Fixed a panic for some mania difficulty calculations on converts
- Updated the difficulty & pp changes from 21.07.27
- Fixed dead loop when reading empty
.osu
files (#2 - @Pure-Peace) - Updated osu's clockrate bugfix for all modes
-
osu & fruits:
-
Fixed specific slider patterns
-
Optimized Bezier, Catmull, and other small things
Benchmarking for osu!standard showed a 25%+ improvement for performance aswell as accuracy
-
-
fruits:
- Fixed tick timing for reverse sliders
-
taiko:
- Micro optimizations
- parse & osu:
- Cleanup and tiny optimizations
- Async beatmap parsing through features
async_tokio
orasync_std
(#1 - @Pure-Peace) - [BREAKING] Hide various parsing related types further inwards, i.e.
rosu_pp::parse::some_type
instead ofrosu_pp::some_type
- Affected types:
DifficultyPoint
,HitObject
,Pos2
,TimingPoint
,HitObjectKind
,PathType
,HitSound
- Affected types:
-
parse:
- Efficiently handle huge amounts of curvepoints
-
osu:
- Fixed panic on unwrapping unavailable hit results
- Fixed occasional underflow when calculating pp with passed_objects
-
taiko:
- Fixed missing flooring of hitwindow for pp calculation
-
fruits:
- Fixed passed objects in star calculation
-
mania:
- Fixed pp calculation on HR