Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
287 changes: 253 additions & 34 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.28", features = ["extension-module", "macros"] }
rosu-mods = { version = "0.3.0", default-features = false, features = ["serde"] }
rosu-pp = { version = "3.1.0", features = ["sync"] }
rosu-mods = { version = "0.4.0", default-features = false, features = ["serde"] }
# rosu-pp = { version = "3.1.0", features = ["sync"] }
rosu-pp = { git = "https://github.com/MaxOhn/rosu-pp", branch = "pp-update", features = ["sync"] }
serde = { version = "1.0.203" }

[profile.release]
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,7 @@ perf = rosu.Performance(
lazer = False, # defaults to True if not specified
misses = 2,
combo = 700,
# If only accuracy is given but no specific hitresults, it is recommended
# to generate hitresults via `HitResultPriority.Fastest`. Otherwise,
# finding the best hitresults can be very slow.
hitresult_priority=rosu.HitResultPriority.Fastest,
hitresult_priority=rosu.HitResultPriority.BestCase,
)

# Each kwarg can also be specified afterwards through setters
Expand All @@ -65,6 +62,13 @@ perf.set_clock_rate(1.4)
perf.set_ar(10.5, True)
perf.set_od(5, False)

# The 'Closest' hitresult generation may be significantly slower but provides
# hitresults that match the given accuracy as close as possible.
perf.set_hitresult_generator(rosu.HitResultGenerator.Closest, rosu.GameMode.Osu)
# Especially for mania, 'Closest' might be too slow in general so let's use
# 'Fast' instead (which is the default anyway for all modes if unspecified).
perf.set_hitresult_generator(rosu.HitResultGenerator.Fast, rosu.GameMode.Mania)

# Calculate for the map
attrs = perf.calculate(map)

Expand Down Expand Up @@ -193,4 +197,4 @@ $ pip install git+https://github.com/MaxOhn/rosu-pp-py
[Rust]: https://www.rust-lang.org
[rosu-pp]: https://github.com/MaxOhn/rosu-pp
[PyO3]: https://github.com/PyO3/pyo3
[Python]: https://www.python.org/downloads/
[Python]: https://www.python.org/downloads/
130 changes: 122 additions & 8 deletions rosu_pp_py.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections.abc import Iterator
from enum import Enum
from typing import List, Mapping, Optional, Union
from collections.abc import Iterator

GameMods = Union[int, str, GameMod, List[Union[GameMod, str, int]]]
GameMod = Mapping[str, Union[str, Optional[GameModSettings]]]
Expand All @@ -26,7 +26,14 @@ class HitResultPriority(Enum):

BestCase = 0
WorstCase = 1
Fastest = 2

class HitResultGenerator(Enum):
"""
A specific implementation of hitresult generation.
"""

Fast = 0
Closest = 1

class Beatmap:
"""
Expand Down Expand Up @@ -385,6 +392,10 @@ class Performance:
Irrelevant for osu!taiko.
`'misses': int`
Specify the amount of misses of a play.
`'legacy_total_score': int`
Specify the legacy total score of a play.

Only relevant for osu!standard.
`'hitresult_priority': HitResultPriority`
Specify how hitresults should be generated.

Expand Down Expand Up @@ -477,6 +488,7 @@ class Performance:
def set_n100(self, n100: Optional[int]) -> None: ...
def set_n50(self, n50: Optional[int]) -> None: ...
def set_misses(self, misses: Optional[int]) -> None: ...
def set_legacy_total_score(self, legacy_total_score: Optional[int]) -> None: ...
def set_hitresult_priority(
self, hitresult_priority: Optional[HitResultPriority]
) -> None: ...
Expand Down Expand Up @@ -673,16 +685,16 @@ class ScoreState:
"""
Maximum combo that the score has had so far. **Not** the maximum
possible combo of the map so far.

Note that for osu!catch only fruits and droplets are considered for combo.

Irrelevant for osu!mania.
"""

osu_large_tick_hits: int
"""
"Large tick" hits for osu!standard.

The meaning depends on the kind of score:
- if set on osu!stable, this field is irrelevant and can be `0`
- if set on osu!lazer *without* `CL`, this field is the amount of hit
Expand All @@ -702,7 +714,7 @@ class ScoreState:
slider_end_hits: int
"""
Amount of successfully hit slider ends.

Only relevant for osu!standard in lazer.
"""

Expand Down Expand Up @@ -736,6 +748,13 @@ class ScoreState:
Amount of current misses (fruits + droplets for osu!catch).
"""

legacy_total_score: int
"""
Legacy total score.

Only relevant for osu!standard.
"""

class DifficultyAttributes:
"""
The result of a difficulty calculation
Expand Down Expand Up @@ -799,6 +818,24 @@ class DifficultyAttributes:
Only available for osu!.
"""

@property
def aim_top_weighted_slider_factor(self) -> Optional[float]:
"""
Describes how much of aim's difficult strain count is contributed to by
sliders.

Only available for osu!.
"""

@property
def speed_top_weighted_slider_factor(self) -> Optional[float]:
"""
Describes how much of speed's difficult strain count is contributed to
by sliders.

Only available for osu!.
"""

@property
def speed_note_count(self) -> Optional[float]:
"""
Expand All @@ -823,6 +860,24 @@ class DifficultyAttributes:
Only available for osu!.
"""

@property
def nested_score_per_object(self) -> Optional[float]:
"""
Only available for osu!.
"""

@property
def legacy_score_base_multiplier(self) -> Optional[float]:
"""
Only available for osu!.
"""

@property
def maximum_legacy_combo_score(self) -> Optional[float]:
"""
Only available for osu!.
"""

@property
def hp(self) -> Optional[float]:
"""
Expand Down Expand Up @@ -955,7 +1010,15 @@ class DifficultyAttributes:
"""
The approach rate.

Only available for osu! and osu!catch.
Only available for osu!.
"""

@property
def preempt(self) -> Optional[float]:
"""
Time preempt (AR time window).

Only available for osu!catch.
"""

@property
Expand All @@ -982,6 +1045,33 @@ class DifficultyAttributes:
Only available for osu!.
"""

@property
def mono_stamina_factor(self) -> Optional[float]:
"""
The ratio of stamina difficulty from mono-color (single color)
streams to total stamina difficulty.

Only available for osu!taiko.
"""

@property
def mechanical_difficulty(self) -> Optional[float]:
"""
The difficulty corresponding to the mechanical skills.

This includes color and stamina combined.

Only available for osu!taiko.
"""

@property
def consistency_factor(self) -> Optional[float]:
"""
The factor corresponding to the consistency of a map.

Only available for osu!taiko.
"""

@property
def max_combo(self) -> int:
"""
Expand Down Expand Up @@ -1042,7 +1132,7 @@ class PerformanceAttributes:
"""
Scaled miss count based on total hits.

Only available for osu! and osu!taiko.
Only available for osu!.
"""

@property
Expand All @@ -1069,6 +1159,30 @@ class PerformanceAttributes:
Only available for osu!taiko and osu!mania.
"""

@property
def combo_based_estimated_miss_count(self) -> Optional[float]:
"""
Only available for osu!.
"""

@property
def score_based_estimated_miss_count(self) -> Optional[float]:
"""
Only *optionally* available for osu!.
"""

@property
def aim_estimated_slider_breaks(self) -> Optional[float]:
"""
Only available for osu!.
"""

@property
def speed_estimated_slider_breaks(self) -> Optional[float]:
"""
Only available for osu!.
"""

@property
def state(self) -> Optional[ScoreState]:
"""
Expand Down
Loading
Loading