return PerformanceAttributes instead of PpResult
This commit is contained in:
+2
-1
@@ -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
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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(¤t) * 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(¤t) * 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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(¤t, 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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user