renamed PpResult+StarResult, minor structural adjustments, documentation update
This commit is contained in:
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
- [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 between `no_leniency` and `all_included` became too small. Hence, the three osu features `no_sliders_no_leniency`, `no_leniency`, and `all_included` were removed. When the `osu` feature is enabled, it will now essentially use `all_included` under the hood.
|
||||
Additionally, instead of importing through `rosu_pp::osu::{version}`, you now have to import through `rosu_pp::osu`.
|
||||
- [BREAKING] Instead of returning `PpResult`, performance calculations now return `PerformanceAttributes` depending on the mode.
|
||||
- [BREAKING] Instead of returning `StarResult`, difficulty calculations now return `DifficultyAttributes` depending on the mode.
|
||||
- [BREAKING] Instead of returning `PpResult`, performance calculations now return `{Mode}PerformanceAttributes` and `PpResult` has been renamed to `PerformanceAttributes`.
|
||||
- [BREAKING] Instead of returning `StarResult`, difficulty calculations now return `{Mode}DifficultyAttributes` and `StarResult` has been renamed to `DifficultyAttributes`.
|
||||
- [BREAKING] Various fields and methods now include `f64` instead of `f32` to stay true to osu!'s original code
|
||||
- added internal binary crate `pp-gen` to calculate difficulty & pp values via `PerformanceCalculator.dll`
|
||||
- osu: Updated up to commit [9fb2402781ad91c197d51aeec716b0000f52c4d1](https://github.com/ppy/osu/commit/9fb2402781ad91c197d51aeec716b0000f52c4d1) (2021-11-12)
|
||||
|
||||
@@ -27,8 +27,6 @@ let map = match Beatmap::parse(file) {
|
||||
|
||||
// If `BeatmapExt` is included, you can make use of
|
||||
// some methods on `Beatmap` to make your life simpler.
|
||||
// If the mode is known, it is recommended to use the
|
||||
// mode's pp calculator, e.g. `TaikoPP`, manually.
|
||||
let result = map.pp()
|
||||
.mods(24) // HDHR
|
||||
.combo(1234)
|
||||
|
||||
+11
-12
@@ -27,16 +27,16 @@ const CATCHER_SIZE: f32 = 106.75;
|
||||
const LEGACY_LAST_TICK_OFFSET: f64 = 36.0;
|
||||
const BASE_SCORING_DISTANCE: f64 = 100.0;
|
||||
|
||||
/// Star calculation for osu!ctb maps
|
||||
/// Difficulty calculation for osu!ctb maps.
|
||||
///
|
||||
/// In case of a partial play, e.g. a fail, one can specify the amount of passed objects.
|
||||
pub fn stars(
|
||||
map: &Beatmap,
|
||||
mods: impl Mods,
|
||||
passed_objects: Option<usize>,
|
||||
) -> DifficultyAttributes {
|
||||
) -> FruitsDifficultyAttributes {
|
||||
if map.hit_objects.len() < 2 {
|
||||
return DifficultyAttributes::default();
|
||||
return FruitsDifficultyAttributes::default();
|
||||
}
|
||||
|
||||
let take = passed_objects.unwrap_or(usize::MAX);
|
||||
@@ -279,7 +279,7 @@ pub fn stars(
|
||||
|
||||
let stars = movement.difficulty_value().sqrt() * STAR_SCALING_FACTOR;
|
||||
|
||||
DifficultyAttributes {
|
||||
FruitsDifficultyAttributes {
|
||||
stars,
|
||||
ar: attributes.ar,
|
||||
n_fruits: fruits,
|
||||
@@ -289,7 +289,7 @@ pub fn stars(
|
||||
}
|
||||
}
|
||||
|
||||
/// Essentially the same as the `stars` function but instead of
|
||||
/// Essentially the same as the [`stars`] function but instead of
|
||||
/// evaluating the final strains, it just returns them as is.
|
||||
///
|
||||
/// Suitable to plot the difficulty of a map over time.
|
||||
@@ -629,10 +629,9 @@ impl<I: Iterator<Item = CatchObject>> Iterator for FruitOrJuice<I> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Various data created through the star calculation.
|
||||
/// This data is necessary to calculate PP.
|
||||
/// The result of a difficulty calculation on an osu!ctb map.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DifficultyAttributes {
|
||||
pub struct FruitsDifficultyAttributes {
|
||||
pub stars: f64,
|
||||
pub max_combo: usize,
|
||||
pub ar: f64,
|
||||
@@ -641,14 +640,14 @@ pub struct DifficultyAttributes {
|
||||
pub n_tiny_droplets: usize,
|
||||
}
|
||||
|
||||
/// Various data created through the pp calculation.
|
||||
/// The result of a performance calculation on an osu!ctb map.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PerformanceAttributes {
|
||||
pub attributes: DifficultyAttributes,
|
||||
pub struct FruitsPerformanceAttributes {
|
||||
pub attributes: FruitsDifficultyAttributes,
|
||||
pub pp: f64,
|
||||
}
|
||||
|
||||
impl PerformanceAttributes {
|
||||
impl FruitsPerformanceAttributes {
|
||||
/// Return the star value.
|
||||
#[inline]
|
||||
pub fn stars(&self) -> f64 {
|
||||
|
||||
+22
-23
@@ -1,7 +1,7 @@
|
||||
use super::{stars, DifficultyAttributes, PerformanceAttributes};
|
||||
use crate::{Beatmap, Mods, PpResult, StarResult};
|
||||
use super::{stars, FruitsDifficultyAttributes, FruitsPerformanceAttributes};
|
||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
|
||||
/// Calculator for pp on osu!ctb maps.
|
||||
/// Performance calculator on osu!ctb maps.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -32,7 +32,7 @@ use crate::{Beatmap, Mods, PpResult, StarResult};
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct FruitsPP<'m> {
|
||||
map: &'m Beatmap,
|
||||
attributes: Option<DifficultyAttributes>,
|
||||
attributes: Option<FruitsDifficultyAttributes>,
|
||||
mods: u32,
|
||||
combo: Option<usize>,
|
||||
|
||||
@@ -62,9 +62,7 @@ impl<'m> FruitsPP<'m> {
|
||||
}
|
||||
}
|
||||
|
||||
/// [`FruitsAttributeProvider`] is implemented by [`DifficultyAttributes`](crate::fruits::DifficultyAttributes),
|
||||
/// [`StarResult`](crate::StarResult), and by [`PpResult`](crate::PpResult) meaning you can give the
|
||||
/// result of a star calculation or a pp calculation.
|
||||
/// Provide the result of previous a difficulty or performance calculation.
|
||||
/// If you already calculated the attributes for the current map-mod combination,
|
||||
/// be sure to put them in here so that they don't have to be recalculated.
|
||||
#[inline]
|
||||
@@ -182,7 +180,7 @@ impl<'m> FruitsPP<'m> {
|
||||
self
|
||||
}
|
||||
|
||||
fn assert_hitresults(self, attributes: DifficultyAttributes) -> FruitsPPInner {
|
||||
fn assert_hitresults(self, attributes: FruitsDifficultyAttributes) -> FruitsPPInner {
|
||||
let correct_combo_hits = self
|
||||
.n_fruits
|
||||
.and_then(|f| self.n_droplets.map(|d| f + d + self.n_misses))
|
||||
@@ -253,7 +251,7 @@ impl<'m> FruitsPP<'m> {
|
||||
}
|
||||
|
||||
/// Calculate all performance related values, including pp and stars.
|
||||
pub fn calculate(mut self) -> PerformanceAttributes {
|
||||
pub fn calculate(mut self) -> FruitsPerformanceAttributes {
|
||||
let attributes = self
|
||||
.attributes
|
||||
.take()
|
||||
@@ -264,7 +262,7 @@ impl<'m> FruitsPP<'m> {
|
||||
}
|
||||
|
||||
struct FruitsPPInner {
|
||||
attributes: DifficultyAttributes,
|
||||
attributes: FruitsDifficultyAttributes,
|
||||
mods: u32,
|
||||
combo: Option<usize>,
|
||||
n_fruits: usize,
|
||||
@@ -275,7 +273,7 @@ struct FruitsPPInner {
|
||||
}
|
||||
|
||||
impl FruitsPPInner {
|
||||
fn calculate(self) -> PerformanceAttributes {
|
||||
fn calculate(self) -> FruitsPerformanceAttributes {
|
||||
let attributes = &self.attributes;
|
||||
let stars = attributes.stars;
|
||||
|
||||
@@ -337,7 +335,7 @@ impl FruitsPPInner {
|
||||
pp *= 0.9;
|
||||
}
|
||||
|
||||
PerformanceAttributes {
|
||||
FruitsPerformanceAttributes {
|
||||
attributes: self.attributes,
|
||||
pp,
|
||||
}
|
||||
@@ -372,27 +370,28 @@ impl FruitsPPInner {
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||
pub trait FruitsAttributeProvider {
|
||||
fn attributes(self) -> Option<DifficultyAttributes>;
|
||||
fn attributes(self) -> Option<FruitsDifficultyAttributes>;
|
||||
}
|
||||
|
||||
impl FruitsAttributeProvider for DifficultyAttributes {
|
||||
impl FruitsAttributeProvider for FruitsDifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<FruitsDifficultyAttributes> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl FruitsAttributeProvider for PerformanceAttributes {
|
||||
impl FruitsAttributeProvider for FruitsPerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<FruitsDifficultyAttributes> {
|
||||
Some(self.attributes)
|
||||
}
|
||||
}
|
||||
|
||||
impl FruitsAttributeProvider for StarResult {
|
||||
impl FruitsAttributeProvider for DifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<FruitsDifficultyAttributes> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Self::Fruits(attributes) = self {
|
||||
Some(attributes)
|
||||
@@ -402,9 +401,9 @@ impl FruitsAttributeProvider for StarResult {
|
||||
}
|
||||
}
|
||||
|
||||
impl FruitsAttributeProvider for PpResult {
|
||||
impl FruitsAttributeProvider for PerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<FruitsDifficultyAttributes> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Self::Fruits(attributes) = self {
|
||||
Some(attributes.attributes)
|
||||
@@ -419,8 +418,8 @@ mod test {
|
||||
use super::*;
|
||||
use crate::Beatmap;
|
||||
|
||||
fn attributes() -> DifficultyAttributes {
|
||||
DifficultyAttributes {
|
||||
fn attributes() -> FruitsDifficultyAttributes {
|
||||
FruitsDifficultyAttributes {
|
||||
n_fruits: 1234,
|
||||
n_droplets: 567,
|
||||
n_tiny_droplets: 2345,
|
||||
|
||||
+46
-34
@@ -25,8 +25,6 @@
|
||||
//!
|
||||
//! // If `BeatmapExt` is included, you can make use of
|
||||
//! // some methods on `Beatmap` to make your life simpler.
|
||||
//! // If the mode is known, it is recommended to use the
|
||||
//! // mode's pp calculator, e.g. `TaikoPP`, manually.
|
||||
//! let result = map.pp()
|
||||
//! .mods(24) // HDHR
|
||||
//! .combo(1234)
|
||||
@@ -153,17 +151,17 @@ pub use taiko::TaikoPP;
|
||||
pub use mods::Mods;
|
||||
pub use parse::{Beatmap, BeatmapAttributes, GameMode, ParseError, ParseResult};
|
||||
|
||||
/// Provides some additional methods on [`Beatmap`](crate::Beatmap).
|
||||
pub trait BeatmapExt {
|
||||
/// Calculate the stars and other attributes of a beatmap which are required for pp calculation.
|
||||
fn stars(&self, mods: impl Mods, passed_objects: Option<usize>) -> StarResult;
|
||||
fn stars(&self, mods: impl Mods, passed_objects: Option<usize>) -> DifficultyAttributes;
|
||||
|
||||
/// Calculate the max pp of a beatmap.
|
||||
///
|
||||
/// If you seek more fine-tuning and options you need to match on the map's
|
||||
/// mode and use the mode's corresponding calculator, e.g. [`TaikoPP`](crate::TaikoPP) for taiko.
|
||||
fn max_pp(&self, mods: u32) -> PpResult;
|
||||
/// If you seek more fine-tuning you can use the [`pp`](BeatmapExt::pp) method.
|
||||
fn max_pp(&self, mods: u32) -> PerformanceAttributes;
|
||||
|
||||
/// Returns a builder to calculate pp and difficulty values.
|
||||
/// Returns a builder for performance calculation.
|
||||
///
|
||||
/// Convenient method that matches on the map's mode to choose the appropriate calculator.
|
||||
fn pp(&self) -> AnyPP<'_>;
|
||||
@@ -177,68 +175,68 @@ pub trait BeatmapExt {
|
||||
}
|
||||
|
||||
impl BeatmapExt for Beatmap {
|
||||
fn stars(&self, mods: impl Mods, passed_objects: Option<usize>) -> StarResult {
|
||||
fn stars(&self, mods: impl Mods, passed_objects: Option<usize>) -> DifficultyAttributes {
|
||||
match self.mode {
|
||||
GameMode::STD => {
|
||||
#[cfg(not(feature = "osu"))]
|
||||
panic!("`osu` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "osu")]
|
||||
StarResult::Osu(osu::stars(self, mods, passed_objects))
|
||||
DifficultyAttributes::Osu(osu::stars(self, mods, passed_objects))
|
||||
}
|
||||
GameMode::MNA => {
|
||||
#[cfg(not(feature = "mania"))]
|
||||
panic!("`mania` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "mania")]
|
||||
StarResult::Mania(mania::stars(self, mods, passed_objects))
|
||||
DifficultyAttributes::Mania(mania::stars(self, mods, passed_objects))
|
||||
}
|
||||
GameMode::TKO => {
|
||||
#[cfg(not(feature = "taiko"))]
|
||||
panic!("`taiko` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "taiko")]
|
||||
StarResult::Taiko(taiko::stars(self, mods, passed_objects))
|
||||
DifficultyAttributes::Taiko(taiko::stars(self, mods, passed_objects))
|
||||
}
|
||||
GameMode::CTB => {
|
||||
#[cfg(not(feature = "fruits"))]
|
||||
panic!("`fruits` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "fruits")]
|
||||
StarResult::Fruits(fruits::stars(self, mods, passed_objects))
|
||||
DifficultyAttributes::Fruits(fruits::stars(self, mods, passed_objects))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn max_pp(&self, mods: u32) -> PpResult {
|
||||
fn max_pp(&self, mods: u32) -> PerformanceAttributes {
|
||||
match self.mode {
|
||||
GameMode::STD => {
|
||||
#[cfg(not(feature = "osu"))]
|
||||
panic!("`osu` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "osu")]
|
||||
PpResult::Osu(OsuPP::new(self).mods(mods).calculate())
|
||||
PerformanceAttributes::Osu(OsuPP::new(self).mods(mods).calculate())
|
||||
}
|
||||
GameMode::MNA => {
|
||||
#[cfg(not(feature = "mania"))]
|
||||
panic!("`mania` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "mania")]
|
||||
PpResult::Mania(ManiaPP::new(self).mods(mods).calculate())
|
||||
PerformanceAttributes::Mania(ManiaPP::new(self).mods(mods).calculate())
|
||||
}
|
||||
GameMode::TKO => {
|
||||
#[cfg(not(feature = "taiko"))]
|
||||
panic!("`taiko` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "taiko")]
|
||||
PpResult::Taiko(TaikoPP::new(self).mods(mods).calculate())
|
||||
PerformanceAttributes::Taiko(TaikoPP::new(self).mods(mods).calculate())
|
||||
}
|
||||
GameMode::CTB => {
|
||||
#[cfg(not(feature = "fruits"))]
|
||||
panic!("`fruits` feature is not enabled");
|
||||
|
||||
#[cfg(feature = "fruits")]
|
||||
PpResult::Fruits(FruitsPP::new(self).mods(mods).calculate())
|
||||
PerformanceAttributes::Fruits(FruitsPP::new(self).mods(mods).calculate())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,21 +292,21 @@ pub struct Strains {
|
||||
pub strains: Vec<f64>,
|
||||
}
|
||||
|
||||
/// Basic enum containing the result of a star calculation based on the mode.
|
||||
/// The result of a difficulty calculation based on the mode.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum StarResult {
|
||||
pub enum DifficultyAttributes {
|
||||
#[cfg(feature = "fruits")]
|
||||
Fruits(fruits::DifficultyAttributes),
|
||||
Fruits(fruits::FruitsDifficultyAttributes),
|
||||
#[cfg(feature = "mania")]
|
||||
Mania(mania::DifficultyAttributes),
|
||||
Mania(mania::ManiaDifficultyAttributes),
|
||||
#[cfg(feature = "osu")]
|
||||
Osu(osu::DifficultyAttributes),
|
||||
Osu(osu::OsuDifficultyAttributes),
|
||||
#[cfg(feature = "taiko")]
|
||||
Taiko(taiko::DifficultyAttributes),
|
||||
Taiko(taiko::TaikoDifficultyAttributes),
|
||||
}
|
||||
|
||||
impl StarResult {
|
||||
/// The final star value.
|
||||
impl DifficultyAttributes {
|
||||
/// The star value.
|
||||
#[inline]
|
||||
pub fn stars(&self) -> f64 {
|
||||
match self {
|
||||
@@ -324,21 +322,21 @@ impl StarResult {
|
||||
}
|
||||
}
|
||||
|
||||
/// Basic struct containing the result of a PP calculation.
|
||||
/// The result of a performance calculation based on the mode.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PpResult {
|
||||
pub enum PerformanceAttributes {
|
||||
#[cfg(feature = "fruits")]
|
||||
Fruits(fruits::PerformanceAttributes),
|
||||
Fruits(fruits::FruitsPerformanceAttributes),
|
||||
#[cfg(feature = "mania")]
|
||||
Mania(mania::PerformanceAttributes),
|
||||
Mania(mania::ManiaPerformanceAttributes),
|
||||
#[cfg(feature = "osu")]
|
||||
Osu(osu::PerformanceAttributes),
|
||||
Osu(osu::OsuPerformanceAttributes),
|
||||
#[cfg(feature = "taiko")]
|
||||
Taiko(taiko::PerformanceAttributes),
|
||||
Taiko(taiko::TaikoPerformanceAttributes),
|
||||
}
|
||||
|
||||
impl PpResult {
|
||||
/// The final pp value.
|
||||
impl PerformanceAttributes {
|
||||
/// The pp value.
|
||||
#[inline]
|
||||
pub fn pp(&self) -> f64 {
|
||||
match self {
|
||||
@@ -353,7 +351,7 @@ impl PpResult {
|
||||
}
|
||||
}
|
||||
|
||||
/// The final star value.
|
||||
/// The star value.
|
||||
#[inline]
|
||||
pub fn stars(&self) -> f64 {
|
||||
match self {
|
||||
@@ -367,6 +365,20 @@ impl PpResult {
|
||||
Self::Taiko(attributes) => attributes.stars(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn difficulty_attributes(&self) -> DifficultyAttributes {
|
||||
match self {
|
||||
#[cfg(feature = "fruits")]
|
||||
Self::Fruits(attributes) => DifficultyAttributes::Fruits(attributes.attributes.clone()),
|
||||
#[cfg(feature = "mania")]
|
||||
Self::Mania(attributes) => DifficultyAttributes::Mania(attributes.attributes),
|
||||
#[cfg(feature = "osu")]
|
||||
Self::Osu(attributes) => DifficultyAttributes::Osu(attributes.attributes.clone()),
|
||||
#[cfg(feature = "taiko")]
|
||||
Self::Taiko(attributes) => DifficultyAttributes::Taiko(attributes.attributes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "osu", feature = "taiko"))]
|
||||
|
||||
+11
-12
@@ -11,18 +11,18 @@ use crate::{parse::HitObject, Beatmap, GameMode, Mods, Strains};
|
||||
const SECTION_LEN: f64 = 400.0;
|
||||
const STAR_SCALING_FACTOR: f64 = 0.018;
|
||||
|
||||
/// Star calculation for osu!mania maps
|
||||
/// Difficulty calculation for osu!mania maps.
|
||||
///
|
||||
/// In case of a partial play, e.g. a fail, one can specify the amount of passed objects.
|
||||
pub fn stars(
|
||||
map: &Beatmap,
|
||||
mods: impl Mods,
|
||||
passed_objects: Option<usize>,
|
||||
) -> DifficultyAttributes {
|
||||
) -> ManiaDifficultyAttributes {
|
||||
let take = passed_objects.unwrap_or_else(|| map.hit_objects.len());
|
||||
|
||||
if take < 2 {
|
||||
return DifficultyAttributes::default();
|
||||
return ManiaDifficultyAttributes::default();
|
||||
}
|
||||
|
||||
let rounded_cs = map.cs.round();
|
||||
@@ -90,10 +90,10 @@ pub fn stars(
|
||||
|
||||
let stars = strain.difficulty_value() * STAR_SCALING_FACTOR;
|
||||
|
||||
DifficultyAttributes { stars }
|
||||
ManiaDifficultyAttributes { stars }
|
||||
}
|
||||
|
||||
/// Essentially the same as the `stars` function but instead of
|
||||
/// Essentially the same as the [`stars`] function but instead of
|
||||
/// evaluating the final strains, it just returns them as is.
|
||||
///
|
||||
/// Suitable to plot the difficulty of a map over time.
|
||||
@@ -169,23 +169,22 @@ impl<'o> DifficultyHitObject<'o> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Various data created through the star calculation.
|
||||
/// This data is necessary to calculate PP.
|
||||
/// The result of a difficulty calculation on an osu!mania map.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct DifficultyAttributes {
|
||||
pub struct ManiaDifficultyAttributes {
|
||||
pub stars: f64,
|
||||
}
|
||||
|
||||
/// Various data created through the pp calculation.
|
||||
/// The result of a performance calculation on an osu!mania map.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct PerformanceAttributes {
|
||||
pub attributes: DifficultyAttributes,
|
||||
pub struct ManiaPerformanceAttributes {
|
||||
pub attributes: ManiaDifficultyAttributes,
|
||||
pub pp_acc: f64,
|
||||
pub pp_strain: f64,
|
||||
pub pp: f64,
|
||||
}
|
||||
|
||||
impl PerformanceAttributes {
|
||||
impl ManiaPerformanceAttributes {
|
||||
/// Return the star value.
|
||||
#[inline]
|
||||
pub fn stars(&self) -> f64 {
|
||||
|
||||
+12
-13
@@ -1,7 +1,7 @@
|
||||
use super::{stars, DifficultyAttributes, PerformanceAttributes};
|
||||
use crate::{Beatmap, Mods, PpResult, StarResult};
|
||||
use super::{stars, ManiaDifficultyAttributes, ManiaPerformanceAttributes};
|
||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
|
||||
/// Calculator for pp on osu!mania maps.
|
||||
/// Performance calculator on osu!mania maps.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -48,9 +48,7 @@ impl<'m> ManiaPP<'m> {
|
||||
}
|
||||
}
|
||||
|
||||
/// [`ManiaAttributeProvider`] is implemented by `f32`, [`StarResult`](crate::StarResult),
|
||||
/// and by [`PpResult`](crate::PpResult) meaning you can give the star rating,
|
||||
/// the result of a star calculation, or the result of a pp calculation.
|
||||
/// Provide the result of previous a difficulty or performance calculation.
|
||||
/// If you already calculated the attributes for the current map-mod combination,
|
||||
/// be sure to put them in here so that they don't have to be recalculated.
|
||||
#[inline]
|
||||
@@ -90,7 +88,7 @@ impl<'m> ManiaPP<'m> {
|
||||
}
|
||||
|
||||
/// Calculate all performance related values, including pp and stars.
|
||||
pub fn calculate(self) -> PerformanceAttributes {
|
||||
pub fn calculate(self) -> ManiaPerformanceAttributes {
|
||||
let stars = self
|
||||
.stars
|
||||
.unwrap_or_else(|| stars(self.map, self.mods, self.passed_objects).stars);
|
||||
@@ -131,8 +129,8 @@ impl<'m> ManiaPP<'m> {
|
||||
|
||||
let pp = (strain_value.powf(1.1) + acc_value.powf(1.1)).powf(1.0 / 1.1) * multiplier;
|
||||
|
||||
PerformanceAttributes {
|
||||
attributes: DifficultyAttributes { stars },
|
||||
ManiaPerformanceAttributes {
|
||||
attributes: ManiaDifficultyAttributes { stars },
|
||||
pp_acc: acc_value,
|
||||
pp_strain: strain_value,
|
||||
pp,
|
||||
@@ -169,6 +167,7 @@ impl<'m> ManiaPP<'m> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||
pub trait ManiaAttributeProvider {
|
||||
fn attributes(self) -> Option<f64>;
|
||||
}
|
||||
@@ -180,21 +179,21 @@ impl ManiaAttributeProvider for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl ManiaAttributeProvider for DifficultyAttributes {
|
||||
impl ManiaAttributeProvider for ManiaDifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
Some(self.stars)
|
||||
}
|
||||
}
|
||||
|
||||
impl ManiaAttributeProvider for PerformanceAttributes {
|
||||
impl ManiaAttributeProvider for ManiaPerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
Some(self.attributes.stars)
|
||||
}
|
||||
}
|
||||
|
||||
impl ManiaAttributeProvider for StarResult {
|
||||
impl ManiaAttributeProvider for DifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
@@ -206,7 +205,7 @@ impl ManiaAttributeProvider for StarResult {
|
||||
}
|
||||
}
|
||||
|
||||
impl ManiaAttributeProvider for PpResult {
|
||||
impl ManiaAttributeProvider for PerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
|
||||
@@ -7,6 +7,7 @@ macro_rules! impl_mods {
|
||||
};
|
||||
}
|
||||
|
||||
/// Abstract type to define mods.
|
||||
pub trait Mods: Copy {
|
||||
const NF: u32 = 1 << 0;
|
||||
const EZ: u32 = 1 << 1;
|
||||
|
||||
+11
-15
@@ -23,17 +23,14 @@ const DIFFICULTY_MULTIPLIER: f64 = 0.0675;
|
||||
const NORMALIZED_RADIUS: f32 = 50.0; // * diameter of 100; easier mental maths.
|
||||
const STACK_DISTANCE: f32 = 3.0;
|
||||
|
||||
/// Star calculation for osu!standard maps.
|
||||
///
|
||||
/// Slider paths aswell as stack leniency are considered.
|
||||
/// Both of these drag the performance down but in turn the values are much more accurate
|
||||
/// Difficulty calculation for osu!standard maps.
|
||||
///
|
||||
/// In case of a partial play, e.g. a fail, one can specify the amount of passed objects.
|
||||
pub fn stars(
|
||||
map: &Beatmap,
|
||||
mods: impl Mods,
|
||||
passed_objects: Option<usize>,
|
||||
) -> DifficultyAttributes {
|
||||
) -> OsuDifficultyAttributes {
|
||||
let take = passed_objects.unwrap_or_else(|| map.hit_objects.len());
|
||||
|
||||
let map_attributes = map.attributes().mods(mods);
|
||||
@@ -41,7 +38,7 @@ pub fn stars(
|
||||
let od = (80.0 - hit_window) / 6.0;
|
||||
|
||||
if take < 2 {
|
||||
return DifficultyAttributes {
|
||||
return OsuDifficultyAttributes {
|
||||
ar: map_attributes.ar,
|
||||
hp: map_attributes.hp,
|
||||
od,
|
||||
@@ -223,7 +220,7 @@ pub fn stars(
|
||||
0.0
|
||||
};
|
||||
|
||||
DifficultyAttributes {
|
||||
OsuDifficultyAttributes {
|
||||
ar: map_attributes.ar,
|
||||
hp: map_attributes.hp,
|
||||
od,
|
||||
@@ -239,7 +236,7 @@ pub fn stars(
|
||||
}
|
||||
}
|
||||
|
||||
/// Essentially the same as the `stars` function but instead of
|
||||
/// Essentially the same as the [`stars`] function but instead of
|
||||
/// evaluating the final strains, it just returns them as is.
|
||||
///
|
||||
/// Suitable to plot the difficulty of a map over time.
|
||||
@@ -544,10 +541,9 @@ fn difficulty_range_ar(ar: f64) -> f64 {
|
||||
crate::difficulty_range(ar, 450.0, 1200.0, 1800.0)
|
||||
}
|
||||
|
||||
/// Various data created through the star calculation.
|
||||
/// This data is necessary to calculate PP.
|
||||
/// The result of a difficulty calculation on an osu!standard map.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DifficultyAttributes {
|
||||
pub struct OsuDifficultyAttributes {
|
||||
pub aim_strain: f64,
|
||||
pub speed_strain: f64,
|
||||
pub flashlight_rating: f64,
|
||||
@@ -562,10 +558,10 @@ pub struct DifficultyAttributes {
|
||||
pub max_combo: usize,
|
||||
}
|
||||
|
||||
/// Various data created through the pp calculation.
|
||||
/// The result of a performance calculation on an osu!standard map.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PerformanceAttributes {
|
||||
pub attributes: DifficultyAttributes,
|
||||
pub struct OsuPerformanceAttributes {
|
||||
pub attributes: OsuDifficultyAttributes,
|
||||
pub pp_acc: f64,
|
||||
pub pp_aim: f64,
|
||||
pub pp_flashlight: f64,
|
||||
@@ -573,7 +569,7 @@ pub struct PerformanceAttributes {
|
||||
pub pp: f64,
|
||||
}
|
||||
|
||||
impl PerformanceAttributes {
|
||||
impl OsuPerformanceAttributes {
|
||||
/// Return the star value.
|
||||
#[inline]
|
||||
pub fn stars(&self) -> f64 {
|
||||
|
||||
+22
-23
@@ -1,7 +1,7 @@
|
||||
use super::{DifficultyAttributes, PerformanceAttributes};
|
||||
use crate::{Beatmap, Mods, PpResult, StarResult};
|
||||
use super::{OsuDifficultyAttributes, OsuPerformanceAttributes};
|
||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
|
||||
/// Calculator for pp on osu!standard maps.
|
||||
/// Performance calculator on osu!standard maps.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -32,7 +32,7 @@ use crate::{Beatmap, Mods, PpResult, StarResult};
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct OsuPP<'m> {
|
||||
map: &'m Beatmap,
|
||||
attributes: Option<DifficultyAttributes>,
|
||||
attributes: Option<OsuDifficultyAttributes>,
|
||||
mods: u32,
|
||||
combo: Option<usize>,
|
||||
acc: Option<f64>,
|
||||
@@ -62,9 +62,7 @@ impl<'m> OsuPP<'m> {
|
||||
}
|
||||
}
|
||||
|
||||
/// [`OsuAttributeProvider`] is implemented by [`DifficultyAttributes`](crate::osu::DifficultyAttributes)
|
||||
/// and by [`PpResult`](crate::PpResult) meaning you can give the
|
||||
/// result of a star calculation or a pp calculation.
|
||||
/// Provide the result of previous a difficulty or performance calculation.
|
||||
/// If you already calculated the attributes for the current map-mod combination,
|
||||
/// be sure to put them in here so that they don't have to be recalculated.
|
||||
#[inline]
|
||||
@@ -199,7 +197,7 @@ impl<'m> OsuPP<'m> {
|
||||
self
|
||||
}
|
||||
|
||||
fn assert_hitresults(self, attributes: DifficultyAttributes) -> OsuPPInner {
|
||||
fn assert_hitresults(self, attributes: OsuDifficultyAttributes) -> OsuPPInner {
|
||||
let mut n300 = self.n300;
|
||||
let mut n100 = self.n100;
|
||||
let mut n50 = self.n50;
|
||||
@@ -281,7 +279,7 @@ impl<'m> OsuPP<'m> {
|
||||
}
|
||||
|
||||
/// Calculate all performance related values, including pp and stars.
|
||||
pub fn calculate(mut self) -> PerformanceAttributes {
|
||||
pub fn calculate(mut self) -> OsuPerformanceAttributes {
|
||||
let attributes = self
|
||||
.attributes
|
||||
.take()
|
||||
@@ -292,7 +290,7 @@ impl<'m> OsuPP<'m> {
|
||||
}
|
||||
|
||||
struct OsuPPInner {
|
||||
attributes: DifficultyAttributes,
|
||||
attributes: OsuDifficultyAttributes,
|
||||
mods: u32,
|
||||
combo: Option<usize>,
|
||||
acc: f64,
|
||||
@@ -306,7 +304,7 @@ struct OsuPPInner {
|
||||
}
|
||||
|
||||
impl OsuPPInner {
|
||||
fn calculate(mut self) -> PerformanceAttributes {
|
||||
fn calculate(mut self) -> OsuPerformanceAttributes {
|
||||
let mut multiplier = 1.12;
|
||||
|
||||
// NF penalty
|
||||
@@ -343,7 +341,7 @@ impl OsuPPInner {
|
||||
.powf(1.0 / 1.1)
|
||||
* multiplier;
|
||||
|
||||
PerformanceAttributes {
|
||||
OsuPerformanceAttributes {
|
||||
attributes: self.attributes,
|
||||
pp_acc: acc_value,
|
||||
pp_aim: aim_value,
|
||||
@@ -565,7 +563,7 @@ impl OsuPPInner {
|
||||
}
|
||||
|
||||
fn calculate_effective_misses(
|
||||
attributes: &DifficultyAttributes,
|
||||
attributes: &OsuDifficultyAttributes,
|
||||
combo: Option<usize>,
|
||||
n_misses: usize,
|
||||
total_hits: f64,
|
||||
@@ -590,27 +588,28 @@ fn calculate_effective_misses(
|
||||
n_misses.max(combo_based_misses.floor() as usize)
|
||||
}
|
||||
|
||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||
pub trait OsuAttributeProvider {
|
||||
fn attributes(self) -> Option<DifficultyAttributes>;
|
||||
fn attributes(self) -> Option<OsuDifficultyAttributes>;
|
||||
}
|
||||
|
||||
impl OsuAttributeProvider for DifficultyAttributes {
|
||||
impl OsuAttributeProvider for OsuDifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<OsuDifficultyAttributes> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl OsuAttributeProvider for PerformanceAttributes {
|
||||
impl OsuAttributeProvider for OsuPerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<OsuDifficultyAttributes> {
|
||||
Some(self.attributes)
|
||||
}
|
||||
}
|
||||
|
||||
impl OsuAttributeProvider for StarResult {
|
||||
impl OsuAttributeProvider for DifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<OsuDifficultyAttributes> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Self::Osu(attributes) = self {
|
||||
Some(attributes)
|
||||
@@ -620,9 +619,9 @@ impl OsuAttributeProvider for StarResult {
|
||||
}
|
||||
}
|
||||
|
||||
impl OsuAttributeProvider for PpResult {
|
||||
impl OsuAttributeProvider for PerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<DifficultyAttributes> {
|
||||
fn attributes(self) -> Option<OsuDifficultyAttributes> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Self::Osu(attributes) = self {
|
||||
Some(attributes.attributes)
|
||||
@@ -699,7 +698,7 @@ mod test {
|
||||
#[test]
|
||||
fn osu_missing_objects() {
|
||||
let map = Beatmap::default();
|
||||
let attributes = DifficultyAttributes::default();
|
||||
let attributes = OsuDifficultyAttributes::default();
|
||||
|
||||
let total_objects = 1234;
|
||||
let n300 = 1000;
|
||||
|
||||
@@ -13,8 +13,10 @@ use std::fmt;
|
||||
use std::io::Error as IOError;
|
||||
use std::num::{ParseFloatError, ParseIntError};
|
||||
|
||||
/// `Result<_, ParseError>`
|
||||
pub type ParseResult<T> = Result<T, ParseError>;
|
||||
|
||||
/// Anything that could go wrong while parsing a [`Beatmap`](crate::Beatmap).
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub enum ParseError {
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
use crate::{Beatmap, GameMode, PpResult, StarResult};
|
||||
use crate::{
|
||||
fruits::FruitsDifficultyAttributes, mania::ManiaDifficultyAttributes,
|
||||
osu::OsuDifficultyAttributes, taiko::TaikoDifficultyAttributes, Beatmap, DifficultyAttributes,
|
||||
GameMode, PerformanceAttributes,
|
||||
};
|
||||
|
||||
#[cfg(feature = "fruits")]
|
||||
use crate::FruitsPP;
|
||||
@@ -12,7 +16,7 @@ use crate::OsuPP;
|
||||
#[cfg(feature = "taiko")]
|
||||
use crate::TaikoPP;
|
||||
|
||||
/// Calculator for pp on maps of any mode.
|
||||
/// Performance calculator on maps of any mode.
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub enum AnyPP<'m> {
|
||||
#[cfg(feature = "fruits")]
|
||||
@@ -43,23 +47,21 @@ impl<'m> AnyPP<'m> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn calculate(self) -> PpResult {
|
||||
pub fn calculate(self) -> PerformanceAttributes {
|
||||
match self {
|
||||
#[cfg(feature = "fruits")]
|
||||
Self::Fruits(f) => PpResult::Fruits(f.calculate()),
|
||||
Self::Fruits(f) => PerformanceAttributes::Fruits(f.calculate()),
|
||||
#[cfg(feature = "mania")]
|
||||
Self::Mania(m) => PpResult::Mania(m.calculate()),
|
||||
Self::Mania(m) => PerformanceAttributes::Mania(m.calculate()),
|
||||
#[cfg(feature = "osu")]
|
||||
Self::Osu(o) => PpResult::Osu(o.calculate()),
|
||||
Self::Osu(o) => PerformanceAttributes::Osu(o.calculate()),
|
||||
#[cfg(feature = "taiko")]
|
||||
Self::Taiko(t) => PpResult::Taiko(t.calculate()),
|
||||
Self::Taiko(t) => PerformanceAttributes::Taiko(t.calculate()),
|
||||
}
|
||||
}
|
||||
|
||||
/// [`AttributeProvider`] is implemented by [`StarResult`](crate::StarResult)
|
||||
/// and [`PpResult`](crate::PpResult) meaning you can give the result of a \
|
||||
/// star calculation or the result of a pp calculation.
|
||||
/// If you already calculated the stars for the current map-mod combination,
|
||||
/// Provide the result of previous a difficulty or performance calculation.
|
||||
/// If you already calculated the attributes for the current map-mod combination,
|
||||
/// be sure to put them in here so that they don't have to be recalculated.
|
||||
#[inline]
|
||||
pub fn attributes(self, attributes: impl AttributeProvider) -> Self {
|
||||
@@ -258,29 +260,58 @@ impl<'m> AnyPP<'m> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||
pub trait AttributeProvider {
|
||||
fn attributes(self) -> StarResult;
|
||||
fn attributes(self) -> DifficultyAttributes;
|
||||
}
|
||||
|
||||
impl AttributeProvider for StarResult {
|
||||
impl AttributeProvider for DifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> StarResult {
|
||||
fn attributes(self) -> DifficultyAttributes {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AttributeProvider for PpResult {
|
||||
impl AttributeProvider for PerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> StarResult {
|
||||
fn attributes(self) -> DifficultyAttributes {
|
||||
match self {
|
||||
#[cfg(feature = "fruits")]
|
||||
Self::Fruits(f) => StarResult::Fruits(f.attributes),
|
||||
Self::Fruits(f) => DifficultyAttributes::Fruits(f.attributes),
|
||||
#[cfg(feature = "mania")]
|
||||
Self::Mania(m) => StarResult::Mania(m.attributes),
|
||||
Self::Mania(m) => DifficultyAttributes::Mania(m.attributes),
|
||||
#[cfg(feature = "osu")]
|
||||
Self::Osu(o) => StarResult::Osu(o.attributes),
|
||||
Self::Osu(o) => DifficultyAttributes::Osu(o.attributes),
|
||||
#[cfg(feature = "taiko")]
|
||||
Self::Taiko(t) => StarResult::Taiko(t.attributes),
|
||||
Self::Taiko(t) => DifficultyAttributes::Taiko(t.attributes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fruits")]
|
||||
impl AttributeProvider for FruitsDifficultyAttributes {
|
||||
fn attributes(self) -> DifficultyAttributes {
|
||||
DifficultyAttributes::Fruits(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "mania")]
|
||||
impl AttributeProvider for ManiaDifficultyAttributes {
|
||||
fn attributes(self) -> DifficultyAttributes {
|
||||
DifficultyAttributes::Mania(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "osu")]
|
||||
impl AttributeProvider for OsuDifficultyAttributes {
|
||||
fn attributes(self) -> DifficultyAttributes {
|
||||
DifficultyAttributes::Osu(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "taiko")]
|
||||
impl AttributeProvider for TaikoDifficultyAttributes {
|
||||
fn attributes(self) -> DifficultyAttributes {
|
||||
DifficultyAttributes::Taiko(self)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-12
@@ -29,18 +29,18 @@ const COLOR_SKILL_MULTIPLIER: f64 = 0.01;
|
||||
const RHYTHM_SKILL_MULTIPLIER: f64 = 0.014;
|
||||
const STAMINA_SKILL_MULTIPLIER: f64 = 0.02;
|
||||
|
||||
/// Star calculation for osu!taiko maps.
|
||||
/// Difficulty calculation for osu!taiko maps.
|
||||
///
|
||||
/// In case of a partial play, e.g. a fail, one can specify the amount of passed objects.
|
||||
pub fn stars(
|
||||
map: &Beatmap,
|
||||
mods: impl Mods,
|
||||
passed_objects: Option<usize>,
|
||||
) -> DifficultyAttributes {
|
||||
) -> TaikoDifficultyAttributes {
|
||||
let take = passed_objects.unwrap_or_else(|| map.hit_objects.len());
|
||||
|
||||
if take < 2 {
|
||||
return DifficultyAttributes { stars: 0.0 };
|
||||
return TaikoDifficultyAttributes { stars: 0.0 };
|
||||
}
|
||||
|
||||
// True if the object at that index is stamina cheese
|
||||
@@ -120,10 +120,10 @@ pub fn stars(
|
||||
|
||||
let stars = rescale(1.4 * separate_rating + 0.5 * combined_rating);
|
||||
|
||||
DifficultyAttributes { stars }
|
||||
TaikoDifficultyAttributes { stars }
|
||||
}
|
||||
|
||||
/// Essentially the same as the `stars` function but instead of
|
||||
/// Essentially the same as the [`stars`] function but instead of
|
||||
/// evaluating the final strains, it just returns them as is.
|
||||
///
|
||||
/// Suitable to plot the difficulty of a map over time.
|
||||
@@ -263,23 +263,22 @@ fn norm(p: f64, a: f64, b: f64, c: f64) -> f64 {
|
||||
(a.powf(p) + b.powf(p) + c.powf(p)).powf(p.recip())
|
||||
}
|
||||
|
||||
/// Various data created through the star calculation.
|
||||
/// This data is necessary to calculate PP.
|
||||
/// The result of a difficulty calculation on an osu!taiko map.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct DifficultyAttributes {
|
||||
pub struct TaikoDifficultyAttributes {
|
||||
pub stars: f64,
|
||||
}
|
||||
|
||||
/// Various data created through the pp calculation.
|
||||
/// The result of a performance calculation on an osu!taiko map.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct PerformanceAttributes {
|
||||
pub attributes: DifficultyAttributes,
|
||||
pub struct TaikoPerformanceAttributes {
|
||||
pub attributes: TaikoDifficultyAttributes,
|
||||
pub pp: f64,
|
||||
pub pp_acc: f64,
|
||||
pub pp_strain: f64,
|
||||
}
|
||||
|
||||
impl PerformanceAttributes {
|
||||
impl TaikoPerformanceAttributes {
|
||||
/// Return the star value.
|
||||
#[inline]
|
||||
pub fn stars(&self) -> f64 {
|
||||
|
||||
+14
-15
@@ -1,7 +1,7 @@
|
||||
use super::{stars, DifficultyAttributes, PerformanceAttributes};
|
||||
use crate::{Beatmap, Mods, PpResult, StarResult};
|
||||
use super::{stars, TaikoDifficultyAttributes, TaikoPerformanceAttributes};
|
||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
|
||||
/// Calculator for pp on osu!taiko maps.
|
||||
/// Performance calculator on osu!taiko maps.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -61,10 +61,8 @@ impl<'m> TaikoPP<'m> {
|
||||
}
|
||||
}
|
||||
|
||||
/// [`TaikoAttributeProvider`] is implemented by `f32`, [`StarResult`](crate::StarResult),
|
||||
/// and by [`PpResult`](crate::PpResult) meaning you can give the star rating,
|
||||
/// the result of a star calculation, or the result of a pp calculation.
|
||||
/// If you already calculated the stars for the current map-mod combination,
|
||||
/// Provide the result of previous a difficulty or performance calculation.
|
||||
/// If you already calculated the attributes for the current map-mod combination,
|
||||
/// be sure to put them in here so that they don't have to be recalculated.
|
||||
#[inline]
|
||||
pub fn attributes(mut self, attributes: impl TaikoAttributeProvider) -> Self {
|
||||
@@ -136,7 +134,7 @@ impl<'m> TaikoPP<'m> {
|
||||
}
|
||||
|
||||
/// Calculate all performance related values, including pp and stars.
|
||||
pub fn calculate(mut self) -> PerformanceAttributes {
|
||||
pub fn calculate(mut self) -> TaikoPerformanceAttributes {
|
||||
let stars = self
|
||||
.stars
|
||||
.unwrap_or_else(|| stars(self.map, self.mods, self.passed_objects).stars);
|
||||
@@ -184,7 +182,7 @@ struct TaikoPPInner<'m> {
|
||||
}
|
||||
|
||||
impl<'m> TaikoPPInner<'m> {
|
||||
fn calculate(self) -> PerformanceAttributes {
|
||||
fn calculate(self) -> TaikoPerformanceAttributes {
|
||||
let mut multiplier = 1.1;
|
||||
|
||||
if self.mods.nf() {
|
||||
@@ -200,8 +198,8 @@ impl<'m> TaikoPPInner<'m> {
|
||||
|
||||
let pp = (strain_value.powf(1.1) + acc_value.powf(1.1)).powf(1.0 / 1.1) * multiplier;
|
||||
|
||||
PerformanceAttributes {
|
||||
attributes: DifficultyAttributes { stars: self.stars },
|
||||
TaikoPerformanceAttributes {
|
||||
attributes: TaikoDifficultyAttributes { stars: self.stars },
|
||||
pp,
|
||||
pp_acc: acc_value,
|
||||
pp_strain: strain_value,
|
||||
@@ -257,6 +255,7 @@ fn difficulty_range_od(od: f64) -> f64 {
|
||||
crate::difficulty_range(od, 20.0, 35.0, 50.0)
|
||||
}
|
||||
|
||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||
pub trait TaikoAttributeProvider {
|
||||
fn attributes(self) -> Option<f64>;
|
||||
}
|
||||
@@ -268,21 +267,21 @@ impl TaikoAttributeProvider for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for DifficultyAttributes {
|
||||
impl TaikoAttributeProvider for TaikoDifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
Some(self.stars)
|
||||
}
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for PerformanceAttributes {
|
||||
impl TaikoAttributeProvider for TaikoPerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
Some(self.attributes.stars)
|
||||
}
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for StarResult {
|
||||
impl TaikoAttributeProvider for DifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
@@ -294,7 +293,7 @@ impl TaikoAttributeProvider for StarResult {
|
||||
}
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for PpResult {
|
||||
impl TaikoAttributeProvider for PerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f64> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
|
||||
Reference in New Issue
Block a user