added 'state' methods to PP calculator structs
This commit is contained in:
+9
-8
@@ -2,19 +2,20 @@
|
|||||||
|
|
||||||
- Added method `Beatmap::from_path` so the file does not have to be created manually for `Beatmap::parse`.
|
- Added method `Beatmap::from_path` so the file does not have to be created manually for `Beatmap::parse`.
|
||||||
- Added a bunch of documentation.
|
- Added a bunch of documentation.
|
||||||
- [BREAKING] Removed the `ParseError` variants `InvalidPathType` and `InvalidTimingSignature` and renamed `InvalidFloatingPoint` to `InvalidDecimalNumber`.
|
|
||||||
- [BREAKING] Removed the `last_control_point` field of `HitObjectKind::Slider` when neither the `osu` nor the `fruits` feature is enabled.
|
|
||||||
- Fixed out of bounds panic on maps with single-control-point linear sliders
|
- Fixed out of bounds panic on maps with single-control-point linear sliders
|
||||||
- [BREAKING] Added the field `TaikoDifficultyAttributes::max_combo`
|
|
||||||
- Added method `Beatmap::bpm`
|
- Added method `Beatmap::bpm`
|
||||||
- Added method `max_combo` for `DifficultyAttributes`, `PerformanceAttributes`, and all `{Mode}PerformanceAttributes`
|
- Added method `max_combo` for `DifficultyAttributes`, `PerformanceAttributes`, and all `{Mode}PerformanceAttributes`
|
||||||
- [BREAKING] Renamed the `attributes` field to `difficulty` for all `{Mode}PerformanceAttributes` structs
|
|
||||||
- Fixed incorrect attributes on maps with only 1 or 2 hit objects for all modes
|
- Fixed incorrect attributes on maps with only 1 or 2 hit objects for all modes
|
||||||
- [BREAKING] Replaced field `FruitsDifficultyAttributes::max_combo` by a method with the same name
|
|
||||||
- Added methods `TaikoDifficultyAttributes::max_combo` and `OsuDifficultyAttributes::max_combo`
|
- Added methods `TaikoDifficultyAttributes::max_combo` and `OsuDifficultyAttributes::max_combo`
|
||||||
- Added structs `{Mode}GradualDifficultyAttributes`. Suitable to calculate a map's difficulty after every or every few objects instead of calling the mode's `stars` function over and over.
|
- Added structs `{Mode}GradualDifficultyAttributes` to calculate a map's difficulty after every or every few objects instead of calling the mode's `stars` function over and over.
|
||||||
- Added structs `{Mode}GradualPerformanceAttributes`. Suitable to calculate the performance on a map after every or every few objects instead of using `{Mode}PP` over and over.
|
- Added structs `{Mode}GradualPerformanceAttributes` to calculate the performance on a map after every or every few objects instead of using `{Mode}PP` over and over.
|
||||||
- Added `BeatmapExt::gradual_difficulty` and `BeatmapExt::gradual_performance` to gradually calculate the difficulty or performance on maps of any mode.
|
- Added `BeatmapExt::gradual_difficulty` and `BeatmapExt::gradual_performance` to gradually calculate the difficulty or performance on maps of any mode, hit object by hit object.
|
||||||
|
- Added methods `{Mode}PP::state` that take a `{Mode}ScoreState` (same for `AnyPP` and `ScoreState`) to set all parameters at once.
|
||||||
|
- [BREAKING] Removed the `ParseError` variants `InvalidPathType` and `InvalidTimingSignature` and renamed `InvalidFloatingPoint` to `InvalidDecimalNumber`.
|
||||||
|
- [BREAKING] Removed the `last_control_point` field of `HitObjectKind::Slider` when neither the `osu` nor the `fruits` feature is enabled.
|
||||||
|
- [BREAKING] Added the field `TaikoDifficultyAttributes::max_combo`
|
||||||
|
- [BREAKING] Renamed the `attributes` field to `difficulty` for all `{Mode}PerformanceAttributes` structs
|
||||||
|
- [BREAKING] Replaced field `FruitsDifficultyAttributes::max_combo` by a method with the same name
|
||||||
|
|
||||||
# v0.3.0
|
# v0.3.0
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub struct FruitsScoreState {
|
|||||||
pub n_tiny_droplets: usize,
|
pub n_tiny_droplets: usize,
|
||||||
/// Amount of current tiny droplet misses (katus).
|
/// Amount of current tiny droplet misses (katus).
|
||||||
pub n_tiny_droplet_misses: usize,
|
pub n_tiny_droplet_misses: usize,
|
||||||
/// Amount of current misses (fruits + droplets).
|
/// Amount of current misses (fruits and droplets).
|
||||||
pub misses: usize,
|
pub misses: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,23 +177,11 @@ impl<'map> FruitsGradualPerformanceAttributes<'map> {
|
|||||||
|
|
||||||
let difficulty = difficulty?;
|
let difficulty = difficulty?;
|
||||||
|
|
||||||
let _ = self.performance.n_fruits.insert(state.n_fruits);
|
|
||||||
let _ = self.performance.n_droplets.insert(state.n_droplets);
|
|
||||||
let _ = self
|
|
||||||
.performance
|
|
||||||
.n_tiny_droplets
|
|
||||||
.insert(state.n_tiny_droplets);
|
|
||||||
let _ = self
|
|
||||||
.performance
|
|
||||||
.n_tiny_droplet_misses
|
|
||||||
.insert(state.n_tiny_droplet_misses);
|
|
||||||
self.performance.n_misses = state.misses;
|
|
||||||
|
|
||||||
let performance = self
|
let performance = self
|
||||||
.performance
|
.performance
|
||||||
.clone()
|
.clone()
|
||||||
.attributes(difficulty)
|
.attributes(difficulty)
|
||||||
.combo(state.max_combo)
|
.state(state)
|
||||||
.passed_objects(self.difficulty.idx)
|
.passed_objects(self.difficulty.idx)
|
||||||
.calculate();
|
.calculate();
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -1,4 +1,4 @@
|
|||||||
use super::{stars, FruitsDifficultyAttributes, FruitsPerformanceAttributes};
|
use super::{stars, FruitsDifficultyAttributes, FruitsPerformanceAttributes, FruitsScoreState};
|
||||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||||
|
|
||||||
/// Performance calculator on osu!ctb maps.
|
/// Performance calculator on osu!ctb maps.
|
||||||
@@ -136,6 +136,10 @@ impl<'map> FruitsPP<'map> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Amount of passed objects for partial plays, e.g. a fail.
|
/// Amount of passed objects for partial plays, e.g. a fail.
|
||||||
|
///
|
||||||
|
/// If you want to calculate the performance after every few objects, instead of
|
||||||
|
/// using [`FruitsPP`] multiple times with different `passed_objects`, you should use
|
||||||
|
/// [`FruitsGradualPerformanceAttributes`](crate::fuits::FruitsGradualPerformanceAttributes).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
||||||
self.passed_objects.replace(passed_objects);
|
self.passed_objects.replace(passed_objects);
|
||||||
@@ -143,6 +147,28 @@ impl<'map> FruitsPP<'map> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provide parameters through an [`FruitsScoreState`].
|
||||||
|
#[inline]
|
||||||
|
pub fn state(mut self, state: FruitsScoreState) -> Self {
|
||||||
|
let FruitsScoreState {
|
||||||
|
max_combo,
|
||||||
|
n_fruits,
|
||||||
|
n_droplets,
|
||||||
|
n_tiny_droplets,
|
||||||
|
n_tiny_droplet_misses,
|
||||||
|
misses,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
self.combo = Some(max_combo);
|
||||||
|
self.n_fruits = Some(n_fruits);
|
||||||
|
self.n_droplets = Some(n_droplets);
|
||||||
|
self.n_tiny_droplets = Some(n_tiny_droplets);
|
||||||
|
self.n_tiny_droplet_misses = Some(n_tiny_droplet_misses);
|
||||||
|
self.n_misses = misses;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate the hit results with respect to the given accuracy between `0` and `100`.
|
/// Generate the hit results with respect to the given accuracy between `0` and `100`.
|
||||||
///
|
///
|
||||||
/// Be sure to set `misses` beforehand! Also, if available, set `attributes` beforehand.
|
/// Be sure to set `misses` beforehand! Also, if available, set `attributes` beforehand.
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ impl<'map> ManiaPP<'map> {
|
|||||||
///
|
///
|
||||||
/// Be sure you also set [`score`](ManiaPP::score) or the final values
|
/// Be sure you also set [`score`](ManiaPP::score) or the final values
|
||||||
/// won't be correct because it will incorrectly assume a score of 1,000,000.
|
/// won't be correct because it will incorrectly assume a score of 1,000,000.
|
||||||
|
///
|
||||||
|
/// If you want to calculate the performance after every few objects, instead of
|
||||||
|
/// using [`ManiaPP`] multiple times with different `passed_objects`, you should use
|
||||||
|
/// [`ManiaGradualPerformanceAttributes`](crate::mania::ManiaGradualPerformanceAttributes).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
||||||
self.passed_objects.replace(passed_objects);
|
self.passed_objects.replace(passed_objects);
|
||||||
|
|||||||
@@ -156,16 +156,11 @@ impl<'map> OsuGradualPerformanceAttributes<'map> {
|
|||||||
let n = n.min(self.difficulty.len()).saturating_sub(1);
|
let n = n.min(self.difficulty.len()).saturating_sub(1);
|
||||||
let difficulty = self.difficulty.nth(n)?;
|
let difficulty = self.difficulty.nth(n)?;
|
||||||
|
|
||||||
let _ = self.performance.n300.insert(state.n300);
|
|
||||||
let _ = self.performance.n100.insert(state.n100);
|
|
||||||
let _ = self.performance.n50.insert(state.n50);
|
|
||||||
self.performance.n_misses = state.misses;
|
|
||||||
|
|
||||||
let performance = self
|
let performance = self
|
||||||
.performance
|
.performance
|
||||||
.clone()
|
.clone()
|
||||||
.attributes(difficulty)
|
.attributes(difficulty)
|
||||||
.combo(state.max_combo)
|
.state(state)
|
||||||
.passed_objects(self.difficulty.idx)
|
.passed_objects(self.difficulty.idx)
|
||||||
.calculate();
|
.calculate();
|
||||||
|
|
||||||
|
|||||||
+22
-2
@@ -1,4 +1,4 @@
|
|||||||
use super::{OsuDifficultyAttributes, OsuPerformanceAttributes};
|
use super::{OsuDifficultyAttributes, OsuPerformanceAttributes, OsuScoreState};
|
||||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||||
|
|
||||||
/// Performance calculator on osu!standard maps.
|
/// Performance calculator on osu!standard maps.
|
||||||
@@ -131,7 +131,7 @@ impl<'map> OsuPP<'map> {
|
|||||||
///
|
///
|
||||||
/// If you want to calculate the performance after every few objects, instead of
|
/// If you want to calculate the performance after every few objects, instead of
|
||||||
/// using [`OsuPP`] multiple times with different `passed_objects`, you should use
|
/// using [`OsuPP`] multiple times with different `passed_objects`, you should use
|
||||||
/// [`OsuGradualPerformanceAttributes`](crate::osu::OsuGradualDifficultyAttributes).
|
/// [`OsuGradualPerformanceAttributes`](crate::osu::OsuGradualPerformanceAttributes).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
||||||
self.passed_objects.replace(passed_objects);
|
self.passed_objects.replace(passed_objects);
|
||||||
@@ -139,6 +139,26 @@ impl<'map> OsuPP<'map> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provide parameters through an [`OsuScoreState`].
|
||||||
|
#[inline]
|
||||||
|
pub fn state(mut self, state: OsuScoreState) -> Self {
|
||||||
|
let OsuScoreState {
|
||||||
|
max_combo,
|
||||||
|
n300,
|
||||||
|
n100,
|
||||||
|
n50,
|
||||||
|
misses,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
self.combo = Some(max_combo);
|
||||||
|
self.n300 = Some(n300);
|
||||||
|
self.n100 = Some(n100);
|
||||||
|
self.n50 = Some(n50);
|
||||||
|
self.n_misses = misses;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate the hit results with respect to the given accuracy between `0` and `100`.
|
/// Generate the hit results with respect to the given accuracy between `0` and `100`.
|
||||||
///
|
///
|
||||||
/// Be sure to set `misses` beforehand!
|
/// Be sure to set `misses` beforehand!
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{Beatmap, DifficultyAttributes, GameMode, PerformanceAttributes};
|
use crate::{Beatmap, DifficultyAttributes, GameMode, PerformanceAttributes, ScoreState};
|
||||||
|
|
||||||
#[cfg(feature = "fruits")]
|
#[cfg(feature = "fruits")]
|
||||||
use crate::fruits::{FruitsDifficultyAttributes, FruitsPP};
|
use crate::fruits::{FruitsDifficultyAttributes, FruitsPP};
|
||||||
@@ -127,6 +127,10 @@ impl<'map> AnyPP<'map> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Amount of passed objects for partial plays, e.g. a fail.
|
/// Amount of passed objects for partial plays, e.g. a fail.
|
||||||
|
///
|
||||||
|
/// If you want to calculate the performance after every few objects, instead of
|
||||||
|
/// using [`AnyPP`] multiple times with different `passed_objects`, you should use
|
||||||
|
/// [`GradualPerformanceAttributes`](crate::GradualPerformanceAttributes).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn passed_objects(self, passed_objects: usize) -> Self {
|
pub fn passed_objects(self, passed_objects: usize) -> Self {
|
||||||
match self {
|
match self {
|
||||||
@@ -141,6 +145,21 @@ impl<'map> AnyPP<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provide parameters through a [`ScoreState`].
|
||||||
|
#[inline]
|
||||||
|
pub fn state(self, state: ScoreState) -> Self {
|
||||||
|
match self {
|
||||||
|
#[cfg(feature = "fruits")]
|
||||||
|
Self::Fruits(f) => Self::Fruits(f.state(state.into())),
|
||||||
|
#[cfg(feature = "mania")]
|
||||||
|
Self::Mania(m) => Self::Mania(m.score(state.score)),
|
||||||
|
#[cfg(feature = "osu")]
|
||||||
|
Self::Osu(o) => Self::Osu(o.state(state.into())),
|
||||||
|
#[cfg(feature = "taiko")]
|
||||||
|
Self::Taiko(t) => Self::Taiko(t.state(state.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the accuracy between 0.0 and 100.0.
|
/// Set the accuracy between 0.0 and 100.0.
|
||||||
///
|
///
|
||||||
/// For some modes this method depends on previously set values.
|
/// For some modes this method depends on previously set values.
|
||||||
|
|||||||
@@ -152,15 +152,11 @@ impl<'map> TaikoGradualPerformanceAttributes<'map> {
|
|||||||
let n = n.min(self.difficulty.len()).saturating_sub(1);
|
let n = n.min(self.difficulty.len()).saturating_sub(1);
|
||||||
let difficulty = self.difficulty.nth(n)?;
|
let difficulty = self.difficulty.nth(n)?;
|
||||||
|
|
||||||
let _ = self.performance.n300.insert(state.n300);
|
|
||||||
let _ = self.performance.n100.insert(state.n100);
|
|
||||||
self.performance.n_misses = state.misses;
|
|
||||||
|
|
||||||
let performance = self
|
let performance = self
|
||||||
.performance
|
.performance
|
||||||
.clone()
|
.clone()
|
||||||
.attributes(difficulty)
|
.attributes(difficulty)
|
||||||
.combo(state.max_combo)
|
.state(state)
|
||||||
.passed_objects(self.difficulty.idx)
|
.passed_objects(self.difficulty.idx)
|
||||||
.calculate();
|
.calculate();
|
||||||
|
|
||||||
|
|||||||
+23
-1
@@ -1,4 +1,4 @@
|
|||||||
use super::{stars, TaikoDifficultyAttributes, TaikoPerformanceAttributes};
|
use super::{stars, TaikoDifficultyAttributes, TaikoPerformanceAttributes, TaikoScoreState};
|
||||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||||
|
|
||||||
/// Performance calculator on osu!taiko maps.
|
/// Performance calculator on osu!taiko maps.
|
||||||
@@ -127,6 +127,10 @@ impl<'map> TaikoPP<'map> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Amount of passed objects for partial plays, e.g. a fail.
|
/// Amount of passed objects for partial plays, e.g. a fail.
|
||||||
|
///
|
||||||
|
/// If you want to calculate the performance after every few objects, instead of
|
||||||
|
/// using [`TaikoPP`] multiple times with different `passed_objects`, you should use
|
||||||
|
/// [`TaikoGradualPerformanceAttributes`](crate::taiko::TaikoGradualPerformanceAttributes).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
||||||
self.passed_objects.replace(passed_objects);
|
self.passed_objects.replace(passed_objects);
|
||||||
@@ -134,6 +138,24 @@ impl<'map> TaikoPP<'map> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provide parameters through a [`TaikoScoreState`].
|
||||||
|
#[inline]
|
||||||
|
pub fn state(mut self, state: TaikoScoreState) -> Self {
|
||||||
|
let TaikoScoreState {
|
||||||
|
max_combo,
|
||||||
|
n300,
|
||||||
|
n100,
|
||||||
|
misses,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
self.combo = Some(max_combo);
|
||||||
|
self.n300 = Some(n300);
|
||||||
|
self.n100 = Some(n100);
|
||||||
|
self.n_misses = misses;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculate all performance related values, including pp and stars.
|
/// Calculate all performance related values, including pp and stars.
|
||||||
pub fn calculate(mut self) -> TaikoPerformanceAttributes {
|
pub fn calculate(mut self) -> TaikoPerformanceAttributes {
|
||||||
let attributes = self
|
let attributes = self
|
||||||
|
|||||||
Reference in New Issue
Block a user