return PerformanceAttributes instead of PpResult

This commit is contained in:
MaxOhn
2021-11-03 16:53:17 +01:00
parent b7caf35bb4
commit 5780559b70
16 changed files with 233 additions and 56 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
## Upcoming ## Upcoming
- added internal binary crate `pp-gen` to calculate difficulty & pp values via `PerformanceCalculator.dll` - added internal binary crate `pp-gen` to calculate difficulty & pp values via `PerformanceCalculator.dll`
- [BREAKING] Instead of returning `PpResult`, performance calculations now return `PerformanceAttributes` depending on the mode.
- osu: Updated up to commit [6944151486e677bfd11f2390163aca9161defbbf](https://github.com/ppy/osu/commit/6944151486e677bfd11f2390163aca9161defbbf) (2021-10-27) - osu: Updated up to commit [6944151486e677bfd11f2390163aca9161defbbf](https://github.com/ppy/osu/commit/6944151486e677bfd11f2390163aca9161defbbf) (2021-10-27)
# v0.2.3 # v0.2.3
@@ -33,7 +34,7 @@
## v0.2.0 ## v0.2.0
- Async beatmap parsing through features `async_tokio` or `async_std` ([#1] - [@Pure-Peace]) - Async beatmap parsing through features `async_tokio` or `async_std` ([#1] - [@Pure-Peace])
- Hide various parsing related types further inwards, i.e. `rosu_pp::parse::some_type` instead of `rosu_pp::some_type` - [BREAKING] Hide various parsing related types further inwards, i.e. `rosu_pp::parse::some_type` instead of `rosu_pp::some_type`
- Affected types: `DifficultyPoint`, `HitObject`, `Pos2`, `TimingPoint`, `HitObjectKind`, `PathType`, `HitSound` - Affected types: `DifficultyPoint`, `HitObject`, `Pos2`, `TimingPoint`, `HitObjectKind`, `PathType`, `HitSound`
## v0.1.1 ## v0.1.1
+23 -4
View File
@@ -18,8 +18,6 @@ use crate::{
Beatmap, Mods, StarResult, Strains, Beatmap, Mods, StarResult, Strains,
}; };
use std::convert::identity;
const SECTION_LENGTH: f32 = 750.0; const SECTION_LENGTH: f32 = 750.0;
const STAR_SCALING_FACTOR: f32 = 0.153; const STAR_SCALING_FACTOR: f32 = 0.153;
@@ -159,7 +157,7 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
} }
HitObjectKind::Spinner { .. } | HitObjectKind::Hold { .. } => Some(None), HitObjectKind::Spinner { .. } | HitObjectKind::Hold { .. } => Some(None),
}) })
.filter_map(identity) .flatten()
.flatten() .flatten()
.take(take); .take(take);
@@ -384,7 +382,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
} }
HitObjectKind::Spinner { .. } | HitObjectKind::Hold { .. } => Some(None), HitObjectKind::Spinner { .. } | HitObjectKind::Hold { .. } => Some(None),
}) })
.filter_map(identity) .flatten()
.flatten(); .flatten();
// Hyper dash business // Hyper dash business
@@ -602,3 +600,24 @@ pub struct DifficultyAttributes {
pub n_droplets: usize, pub n_droplets: usize,
pub n_tiny_droplets: usize, pub n_tiny_droplets: usize,
} }
/// Various data created through the pp calculation.
#[derive(Clone, Debug, Default)]
pub struct PerformanceAttributes {
pub attributes: DifficultyAttributes,
pub pp: f32,
}
impl PerformanceAttributes {
/// Return the star value.
#[inline]
pub fn stars(&self) -> f32 {
self.attributes.stars
}
/// Return the performance point value.
#[inline]
pub fn pp(&self) -> f32 {
self.pp
}
}
+1 -1
View File
@@ -57,7 +57,7 @@ impl Movement {
pub(crate) fn process(&mut self, current: &DifficultyObject) { pub(crate) fn process(&mut self, current: &DifficultyObject) {
self.current_strain *= strain_decay(current.delta); self.current_strain *= strain_decay(current.delta);
self.current_strain += self.strain_value_of(&current) * SKILL_MULTIPLIER; self.current_strain += self.strain_value_of(current) * SKILL_MULTIPLIER;
self.current_section_peak = self.current_strain.max(self.current_section_peak); self.current_section_peak = self.current_strain.max(self.current_section_peak);
self.prev_time.replace(current.start_time); self.prev_time.replace(current.start_time);
} }
+16 -7
View File
@@ -1,4 +1,4 @@
use super::{stars, DifficultyAttributes}; use super::{stars, DifficultyAttributes, PerformanceAttributes};
use crate::{Beatmap, Mods, PpResult, StarResult}; use crate::{Beatmap, Mods, PpResult, StarResult};
/// Calculator for pp on osu!ctb maps. /// Calculator for pp on osu!ctb maps.
@@ -241,7 +241,7 @@ impl<'m> FruitsPP<'m> {
/// Returns an object which contains the pp and [`DifficultyAttributes`](crate::fruits::DifficultyAttributes) /// Returns an object which contains the pp and [`DifficultyAttributes`](crate::fruits::DifficultyAttributes)
/// containing stars and other attributes. /// containing stars and other attributes.
pub fn calculate(mut self) -> PpResult { pub fn calculate(mut self) -> PerformanceAttributes {
let attributes = self.attributes.take().unwrap_or_else(|| { let attributes = self.attributes.take().unwrap_or_else(|| {
stars(self.map, self.mods, self.passed_objects) stars(self.map, self.mods, self.passed_objects)
.attributes() .attributes()
@@ -310,10 +310,7 @@ impl<'m> FruitsPP<'m> {
pp *= 0.9; pp *= 0.9;
} }
PpResult { PerformanceAttributes { attributes, pp }
pp,
attributes: StarResult::Fruits(attributes),
}
} }
#[inline] #[inline]
@@ -358,6 +355,13 @@ impl FruitsAttributeProvider for DifficultyAttributes {
} }
} }
impl FruitsAttributeProvider for PerformanceAttributes {
#[inline]
fn attributes(self) -> Option<DifficultyAttributes> {
Some(self.attributes)
}
}
impl FruitsAttributeProvider for StarResult { impl FruitsAttributeProvider for StarResult {
#[inline] #[inline]
fn attributes(self) -> Option<DifficultyAttributes> { fn attributes(self) -> Option<DifficultyAttributes> {
@@ -373,7 +377,12 @@ impl FruitsAttributeProvider for StarResult {
impl FruitsAttributeProvider for PpResult { impl FruitsAttributeProvider for PpResult {
#[inline] #[inline]
fn attributes(self) -> Option<DifficultyAttributes> { fn attributes(self) -> Option<DifficultyAttributes> {
self.attributes.attributes() #[allow(irrefutable_let_patterns)]
if let Self::Fruits(attributes) = self {
Some(attributes.attributes)
} else {
None
}
} }
} }
+33 -9
View File
@@ -271,28 +271,28 @@ impl BeatmapExt for Beatmap {
panic!("`osu` feature is not enabled"); panic!("`osu` feature is not enabled");
#[cfg(feature = "osu")] #[cfg(feature = "osu")]
OsuPP::new(self).mods(mods).calculate() PpResult::Osu(OsuPP::new(self).mods(mods).calculate())
} }
GameMode::MNA => { GameMode::MNA => {
#[cfg(not(feature = "mania"))] #[cfg(not(feature = "mania"))]
panic!("`mania` feature is not enabled"); panic!("`mania` feature is not enabled");
#[cfg(feature = "mania")] #[cfg(feature = "mania")]
ManiaPP::new(self).mods(mods).calculate() PpResult::Mania(ManiaPP::new(self).mods(mods).calculate())
} }
GameMode::TKO => { GameMode::TKO => {
#[cfg(not(feature = "taiko"))] #[cfg(not(feature = "taiko"))]
panic!("`osu` feature is not enabled"); panic!("`osu` feature is not enabled");
#[cfg(feature = "taiko")] #[cfg(feature = "taiko")]
TaikoPP::new(self).mods(mods).calculate() PpResult::Taiko(TaikoPP::new(self).mods(mods).calculate())
} }
GameMode::CTB => { GameMode::CTB => {
#[cfg(not(feature = "fruits"))] #[cfg(not(feature = "fruits"))]
panic!("`fruits` feature is not enabled"); panic!("`fruits` feature is not enabled");
#[cfg(feature = "fruits")] #[cfg(feature = "fruits")]
FruitsPP::new(self).mods(mods).calculate() PpResult::Fruits(FruitsPP::new(self).mods(mods).calculate())
} }
} }
} }
@@ -406,22 +406,46 @@ impl StarResult {
/// Basic struct containing the result of a PP calculation. /// Basic struct containing the result of a PP calculation.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PpResult { pub enum PpResult {
pub pp: f32, #[cfg(feature = "fruits")]
pub attributes: StarResult, Fruits(fruits::PerformanceAttributes),
#[cfg(feature = "mania")]
Mania(mania::PerformanceAttributes),
#[cfg(feature = "osu")]
Osu(osu::PerformanceAttributes),
#[cfg(feature = "taiko")]
Taiko(taiko::PerformanceAttributes),
} }
impl PpResult { impl PpResult {
/// The final pp value. /// The final pp value.
#[inline] #[inline]
pub fn pp(&self) -> f32 { pub fn pp(&self) -> f32 {
self.pp match self {
#[cfg(feature = "fruits")]
Self::Fruits(attributes) => attributes.pp,
#[cfg(feature = "mania")]
Self::Mania(attributes) => attributes.pp,
#[cfg(feature = "osu")]
Self::Osu(attributes) => attributes.pp,
#[cfg(feature = "taiko")]
Self::Taiko(attributes) => attributes.pp,
}
} }
/// The final star value. /// The final star value.
#[inline] #[inline]
pub fn stars(&self) -> f32 { pub fn stars(&self) -> f32 {
self.attributes.stars() match self {
#[cfg(feature = "fruits")]
Self::Fruits(attributes) => attributes.stars(),
#[cfg(feature = "mania")]
Self::Mania(attributes) => attributes.stars(),
#[cfg(feature = "osu")]
Self::Osu(attributes) => attributes.stars(),
#[cfg(feature = "taiko")]
Self::Taiko(attributes) => attributes.stars(),
}
} }
} }
+24 -1
View File
@@ -167,7 +167,30 @@ impl<'o> DifficultyHitObject<'o> {
/// Various data created through the star calculation. /// Various data created through the star calculation.
/// This data is necessary to calculate PP. /// This data is necessary to calculate PP.
#[derive(Clone, Debug, Default)] #[derive(Copy, Clone, Debug, Default)]
pub struct DifficultyAttributes { pub struct DifficultyAttributes {
pub stars: f32, pub stars: f32,
} }
/// Various data created through the pp calculation.
#[derive(Copy, Clone, Debug, Default)]
pub struct PerformanceAttributes {
pub attributes: DifficultyAttributes,
pub pp_acc: f32,
pub pp_strain: f32,
pub pp: f32,
}
impl PerformanceAttributes {
/// Return the star value.
#[inline]
pub fn stars(&self) -> f32 {
self.attributes.stars
}
/// Return the performance point value.
#[inline]
pub fn pp(&self) -> f32 {
self.pp
}
}
+19 -5
View File
@@ -1,4 +1,4 @@
use super::{stars, DifficultyAttributes}; use super::{stars, DifficultyAttributes, PerformanceAttributes};
use crate::{Beatmap, Mods, PpResult, StarResult}; use crate::{Beatmap, Mods, PpResult, StarResult};
/// Calculator for pp on osu!mania maps. /// Calculator for pp on osu!mania maps.
@@ -90,7 +90,7 @@ impl<'m> ManiaPP<'m> {
} }
/// Returns an object which contains the pp and stars. /// Returns an object which contains the pp and stars.
pub fn calculate(self) -> PpResult { pub fn calculate(self) -> PerformanceAttributes {
let stars = self let stars = self
.stars .stars
.unwrap_or_else(|| stars(self.map, self.mods, self.passed_objects).stars()); .unwrap_or_else(|| stars(self.map, self.mods, self.passed_objects).stars());
@@ -131,9 +131,11 @@ impl<'m> ManiaPP<'m> {
let pp = (strain_value.powf(1.1) + acc_value.powf(1.1)).powf(1.0 / 1.1) * multiplier; let pp = (strain_value.powf(1.1) + acc_value.powf(1.1)).powf(1.0 / 1.1) * multiplier;
PpResult { PerformanceAttributes {
attributes: DifficultyAttributes { stars },
pp_acc: acc_value,
pp_strain: strain_value,
pp, pp,
attributes: StarResult::Mania(DifficultyAttributes { stars }),
} }
} }
@@ -185,6 +187,13 @@ impl ManiaAttributeProvider for DifficultyAttributes {
} }
} }
impl ManiaAttributeProvider for PerformanceAttributes {
#[inline]
fn attributes(self) -> Option<f32> {
Some(self.attributes.stars)
}
}
impl ManiaAttributeProvider for StarResult { impl ManiaAttributeProvider for StarResult {
#[inline] #[inline]
fn attributes(self) -> Option<f32> { fn attributes(self) -> Option<f32> {
@@ -200,6 +209,11 @@ impl ManiaAttributeProvider for StarResult {
impl ManiaAttributeProvider for PpResult { impl ManiaAttributeProvider for PpResult {
#[inline] #[inline]
fn attributes(self) -> Option<f32> { fn attributes(self) -> Option<f32> {
self.attributes.attributes() #[allow(irrefutable_let_patterns)]
if let Self::Mania(attributes) = self {
Some(attributes.attributes.stars)
} else {
None
}
} }
} }
+1 -1
View File
@@ -65,7 +65,7 @@ impl Strain {
#[inline] #[inline]
pub(crate) fn process(&mut self, current: &DifficultyHitObject) { pub(crate) fn process(&mut self, current: &DifficultyHitObject) {
self.current_strain *= self.strain_decay(current.delta); self.current_strain *= self.strain_decay(current.delta);
self.current_strain += self.strain_value_of(&current) * SKILL_MULTIPLIER; self.current_strain += self.strain_value_of(current) * SKILL_MULTIPLIER;
self.current_section_peak = self.current_strain.max(self.current_section_peak); self.current_section_peak = self.current_strain.max(self.current_section_peak);
self.prev_time.replace(current.start_time); self.prev_time.replace(current.start_time);
} }
+25
View File
@@ -22,3 +22,28 @@ pub struct DifficultyAttributes {
pub stars: f32, pub stars: f32,
pub max_combo: usize, pub max_combo: usize,
} }
/// Various data created through the pp calculation.
#[derive(Clone, Debug, Default)]
pub struct PerformanceAttributes {
pub attributes: DifficultyAttributes,
pub pp_acc: f32,
pub pp_aim: f32,
pub pp_flashlight: f32,
pub pp_speed: f32,
pub pp: f32,
}
impl PerformanceAttributes {
/// Return the star value.
#[inline]
pub fn stars(&self) -> f32 {
self.attributes.stars
}
/// Return the performance point value.
#[inline]
pub fn pp(&self) -> f32 {
self.pp
}
}
+27 -10
View File
@@ -1,4 +1,4 @@
use super::DifficultyAttributes; use super::{DifficultyAttributes, PerformanceAttributes};
use crate::{Beatmap, Mods, PpResult, StarResult}; use crate::{Beatmap, Mods, PpResult, StarResult};
/// Calculator for pp on osu!standard maps. /// Calculator for pp on osu!standard maps.
@@ -238,21 +238,21 @@ impl<'m> OsuPP<'m> {
/// Returns an object which contains the pp and [`DifficultyAttributes`](crate::osu::DifficultyAttributes) /// Returns an object which contains the pp and [`DifficultyAttributes`](crate::osu::DifficultyAttributes)
/// containing stars and other attributes. /// containing stars and other attributes.
#[cfg(feature = "no_leniency")] #[cfg(feature = "no_leniency")]
pub fn calculate(self) -> PpResult { pub fn calculate(self) -> PerformanceAttributes {
self.calculate_with_func(super::no_leniency::stars) self.calculate_with_func(super::no_leniency::stars)
} }
/// Returns an object which contains the pp and [`DifficultyAttributes`](crate::osu::DifficultyAttributes) /// Returns an object which contains the pp and [`DifficultyAttributes`](crate::osu::DifficultyAttributes)
/// containing stars and other attributes. /// containing stars and other attributes.
#[cfg(feature = "no_sliders_no_leniency")] #[cfg(feature = "no_sliders_no_leniency")]
pub fn calculate(self) -> PpResult { pub fn calculate(self) -> PerformanceAttributes {
self.calculate_with_func(super::no_sliders_no_leniency::stars) self.calculate_with_func(super::no_sliders_no_leniency::stars)
} }
/// Returns an object which contains the pp and [`DifficultyAttributes`](crate::osu::DifficultyAttributes) /// Returns an object which contains the pp and [`DifficultyAttributes`](crate::osu::DifficultyAttributes)
/// containing stars and other attributes. /// containing stars and other attributes.
#[cfg(feature = "all_included")] #[cfg(feature = "all_included")]
pub fn calculate(self) -> PpResult { pub fn calculate(self) -> PerformanceAttributes {
self.calculate_with_func(super::all_included::stars) self.calculate_with_func(super::all_included::stars)
} }
@@ -262,14 +262,14 @@ impl<'m> OsuPP<'m> {
feature = "no_sliders_no_leniency", feature = "no_sliders_no_leniency",
feature = "all_included" feature = "all_included"
)))] )))]
pub(crate) fn calculate(self) -> PpResult { pub(crate) fn calculate(self) -> PerformanceAttributes {
unreachable!() unreachable!()
} }
fn calculate_with_func( fn calculate_with_func(
mut self, mut self,
stars_func: impl FnOnce(&Beatmap, u32, Option<usize>) -> StarResult, stars_func: impl FnOnce(&Beatmap, u32, Option<usize>) -> StarResult,
) -> PpResult { ) -> PerformanceAttributes {
if self.attributes.is_none() { if self.attributes.is_none() {
let attributes = stars_func(self.map, self.mods, self.passed_objects) let attributes = stars_func(self.map, self.mods, self.passed_objects)
.attributes() .attributes()
@@ -316,9 +316,14 @@ impl<'m> OsuPP<'m> {
.powf(1.0 / 1.1) .powf(1.0 / 1.1)
* multiplier; * multiplier;
let attributes = StarResult::Osu(self.attributes.unwrap()); PerformanceAttributes {
attributes: self.attributes.unwrap(),
PpResult { pp, attributes } pp_acc: aim_value,
pp_aim: aim_value,
pp_flashlight: flashlight_value,
pp_speed: speed_value,
pp,
}
} }
fn compute_aim_value(&self, total_hits: f32) -> f32 { fn compute_aim_value(&self, total_hits: f32) -> f32 {
@@ -563,6 +568,13 @@ impl OsuAttributeProvider for DifficultyAttributes {
} }
} }
impl OsuAttributeProvider for PerformanceAttributes {
#[inline]
fn attributes(self) -> Option<DifficultyAttributes> {
Some(self.attributes)
}
}
impl OsuAttributeProvider for StarResult { impl OsuAttributeProvider for StarResult {
#[inline] #[inline]
fn attributes(self) -> Option<DifficultyAttributes> { fn attributes(self) -> Option<DifficultyAttributes> {
@@ -578,7 +590,12 @@ impl OsuAttributeProvider for StarResult {
impl OsuAttributeProvider for PpResult { impl OsuAttributeProvider for PpResult {
#[inline] #[inline]
fn attributes(self) -> Option<DifficultyAttributes> { fn attributes(self) -> Option<DifficultyAttributes> {
self.attributes.attributes() #[allow(irrefutable_let_patterns)]
if let Self::Osu(attributes) = self {
Some(attributes.attributes)
} else {
None
}
} }
} }
+1 -1
View File
@@ -30,7 +30,7 @@ enum OsuObjectKind {
} }
impl OsuObject { impl OsuObject {
#[allow(clippy::clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn new( pub(crate) fn new(
h: &HitObject, h: &HitObject,
map: &Beatmap, map: &Beatmap,
@@ -61,7 +61,7 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
let clock_rate = attributes.clock_rate; let clock_rate = attributes.clock_rate;
let mut max_combo = 0; let mut max_combo = 0;
let mut state = SliderState::new(&map); let mut state = SliderState::new(map);
let mut hit_objects = map let mut hit_objects = map
.hit_objects .hit_objects
@@ -76,7 +76,7 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
HitObjectKind::Slider { HitObjectKind::Slider {
pixel_len, repeats, .. pixel_len, repeats, ..
} => { } => {
max_combo += state.count_ticks(h.start_time, *pixel_len, *repeats, &map); max_combo += state.count_ticks(h.start_time, *pixel_len, *repeats, map);
OsuObject::from(h, clock_rate) OsuObject::from(h, clock_rate)
} }
+14 -5
View File
@@ -46,13 +46,13 @@ impl<'m> AnyPP<'m> {
pub fn calculate(self) -> PpResult { pub fn calculate(self) -> PpResult {
match self { match self {
#[cfg(feature = "fruits")] #[cfg(feature = "fruits")]
Self::Fruits(f) => f.calculate(), Self::Fruits(f) => PpResult::Fruits(f.calculate()),
#[cfg(feature = "mania")] #[cfg(feature = "mania")]
Self::Mania(m) => m.calculate(), Self::Mania(m) => PpResult::Mania(m.calculate()),
#[cfg(feature = "osu")] #[cfg(feature = "osu")]
Self::Osu(o) => o.calculate(), Self::Osu(o) => PpResult::Osu(o.calculate()),
#[cfg(feature = "taiko")] #[cfg(feature = "taiko")]
Self::Taiko(t) => t.calculate(), Self::Taiko(t) => PpResult::Taiko(t.calculate()),
} }
} }
@@ -272,6 +272,15 @@ impl AttributeProvider for StarResult {
impl AttributeProvider for PpResult { impl AttributeProvider for PpResult {
#[inline] #[inline]
fn attributes(self) -> StarResult { fn attributes(self) -> StarResult {
self.attributes match self {
#[cfg(feature = "fruits")]
Self::Fruits(f) => StarResult::Fruits(f.attributes),
#[cfg(feature = "mania")]
Self::Mania(m) => StarResult::Mania(m.attributes),
#[cfg(feature = "osu")]
Self::Osu(o) => StarResult::Osu(o.attributes),
#[cfg(feature = "taiko")]
Self::Taiko(t) => StarResult::Taiko(t.attributes),
}
} }
} }
+24 -1
View File
@@ -261,7 +261,30 @@ fn norm(p: f32, a: f32, b: f32, c: f32) -> f32 {
/// Various data created through the star calculation. /// Various data created through the star calculation.
/// This data is necessary to calculate PP. /// This data is necessary to calculate PP.
#[derive(Clone, Debug, Default)] #[derive(Copy, Clone, Debug, Default)]
pub struct DifficultyAttributes { pub struct DifficultyAttributes {
pub stars: f32, pub stars: f32,
} }
/// Various data created through the pp calculation.
#[derive(Copy, Clone, Debug, Default)]
pub struct PerformanceAttributes {
pub attributes: DifficultyAttributes,
pub pp: f32,
pub pp_acc: f32,
pub pp_strain: f32,
}
impl PerformanceAttributes {
/// Return the star value.
#[inline]
pub fn stars(&self) -> f32 {
self.attributes.stars
}
/// Return the performance point value.
#[inline]
pub fn pp(&self) -> f32 {
self.pp
}
}
+20 -6
View File
@@ -1,4 +1,4 @@
use super::{stars, DifficultyAttributes}; use super::{stars, DifficultyAttributes, PerformanceAttributes};
use crate::{Beatmap, Mods, PpResult, StarResult}; use crate::{Beatmap, Mods, PpResult, StarResult};
/// Calculator for pp on osu!taiko maps. /// Calculator for pp on osu!taiko maps.
@@ -136,7 +136,7 @@ impl<'m> TaikoPP<'m> {
} }
/// Returns an object which contains the pp and stars. /// Returns an object which contains the pp and stars.
pub fn calculate(mut self) -> PpResult { pub fn calculate(mut self) -> PerformanceAttributes {
let stars = self let stars = self
.stars .stars
.unwrap_or_else(|| stars(self.map, self.mods, self.passed_objects).stars()); .unwrap_or_else(|| stars(self.map, self.mods, self.passed_objects).stars());
@@ -176,9 +176,11 @@ impl<'m> TaikoPP<'m> {
let pp = (strain_value.powf(1.1) + acc_value.powf(1.1)).powf(1.0 / 1.1) * multiplier; let pp = (strain_value.powf(1.1) + acc_value.powf(1.1)).powf(1.0 / 1.1) * multiplier;
PpResult { PerformanceAttributes {
attributes: DifficultyAttributes { stars },
pp, pp,
attributes: StarResult::Taiko(DifficultyAttributes { stars }), pp_acc: acc_value,
pp_strain: strain_value,
} }
} }
@@ -253,11 +255,18 @@ impl TaikoAttributeProvider for DifficultyAttributes {
} }
} }
impl TaikoAttributeProvider for PerformanceAttributes {
#[inline]
fn attributes(self) -> Option<f32> {
Some(self.attributes.stars)
}
}
impl TaikoAttributeProvider for StarResult { impl TaikoAttributeProvider for StarResult {
#[inline] #[inline]
fn attributes(self) -> Option<f32> { fn attributes(self) -> Option<f32> {
#[allow(irrefutable_let_patterns)] #[allow(irrefutable_let_patterns)]
if let StarResult::Taiko(attributes) = self { if let Self::Taiko(attributes) = self {
Some(attributes.stars) Some(attributes.stars)
} else { } else {
None None
@@ -268,6 +277,11 @@ impl TaikoAttributeProvider for StarResult {
impl TaikoAttributeProvider for PpResult { impl TaikoAttributeProvider for PpResult {
#[inline] #[inline]
fn attributes(self) -> Option<f32> { fn attributes(self) -> Option<f32> {
self.attributes.attributes() #[allow(irrefutable_let_patterns)]
if let Self::Taiko(attributes) = self {
Some(attributes.attributes.stars)
} else {
None
}
} }
} }
+1 -2
View File
@@ -50,8 +50,7 @@ impl Skill {
#[inline] #[inline]
pub(crate) fn process(&mut self, current: &DifficultyObject, cheese: &[bool]) { pub(crate) fn process(&mut self, current: &DifficultyObject, cheese: &[bool]) {
self.current_strain *= self.strain_decay(current.delta); self.current_strain *= self.strain_decay(current.delta);
self.current_strain += self.current_strain += self.kind.strain_value_of(current, cheese) * self.skill_multiplier();
self.kind.strain_value_of(&current, cheese) * self.skill_multiplier();
self.current_section_peak = self.current_section_peak.max(self.current_strain); self.current_section_peak = self.current_section_peak.max(self.current_strain);
self.prev_time.replace(current.start_time); self.prev_time.replace(current.start_time);
} }