added distinct strains struct for each mode
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
- __Fixes:__
|
- __Fixes:__
|
||||||
- Slider velocity is now adjusted properly for taiko converts
|
- Slider velocity is now adjusted properly for taiko converts
|
||||||
|
- __Breaking changes:__
|
||||||
|
- Replaced the simple `Strains` struct with a new struct `{Mode}Strains` that contains more detail w.r.t. the mode.
|
||||||
|
|
||||||
# v0.6.0 (2022-07-05)
|
# v0.6.0 (2022-07-05)
|
||||||
|
|
||||||
|
|||||||
+23
-7
@@ -16,9 +16,7 @@ use movement::Movement;
|
|||||||
pub use pp::*;
|
pub use pp::*;
|
||||||
use slider_state::SliderState;
|
use slider_state::SliderState;
|
||||||
|
|
||||||
use crate::{
|
use crate::{catch::fruit_or_juice::FruitParams, curve::CurveBuffers, Beatmap, Mods, OsuStars};
|
||||||
catch::fruit_or_juice::FruitParams, curve::CurveBuffers, Beatmap, Mods, OsuStars, Strains,
|
|
||||||
};
|
|
||||||
|
|
||||||
const SECTION_LENGTH: f64 = 750.0;
|
const SECTION_LENGTH: f64 = 750.0;
|
||||||
const STAR_SCALING_FACTOR: f64 = 0.153;
|
const STAR_SCALING_FACTOR: f64 = 0.153;
|
||||||
@@ -110,17 +108,35 @@ impl<'map> CatchStars<'map> {
|
|||||||
///
|
///
|
||||||
/// Suitable to plot the difficulty of a map over time.
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn strains(self) -> Strains {
|
pub fn strains(self) -> CatchStrains {
|
||||||
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
||||||
let (movement, _) = calculate_movement(self);
|
let (movement, _) = calculate_movement(self);
|
||||||
|
|
||||||
Strains {
|
CatchStrains {
|
||||||
section_length: SECTION_LENGTH * clock_rate,
|
section_len: SECTION_LENGTH * clock_rate,
|
||||||
strains: movement.strain_peaks,
|
movement: movement.strain_peaks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of calculating the strains on a osu!catch map.
|
||||||
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct CatchStrains {
|
||||||
|
/// Time in ms inbetween two strains.
|
||||||
|
pub section_len: f64,
|
||||||
|
/// Strain peaks of the movement skill.
|
||||||
|
pub movement: Vec<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CatchStrains {
|
||||||
|
/// Returns the number of strain peaks per skill.
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.movement.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn calculate_movement(params: CatchStars<'_>) -> (Movement, CatchDifficultyAttributes) {
|
fn calculate_movement(params: CatchStars<'_>) -> (Movement, CatchDifficultyAttributes) {
|
||||||
let CatchStars {
|
let CatchStars {
|
||||||
map,
|
map,
|
||||||
|
|||||||
+42
-13
@@ -286,10 +286,10 @@ impl BeatmapExt for Beatmap {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn strains(&self, mods: u32) -> Strains {
|
fn strains(&self, mods: u32) -> Strains {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
GameMode::STD => OsuStars::new(self).mods(mods).strains(),
|
GameMode::STD => Strains::Osu(OsuStars::new(self).mods(mods).strains()),
|
||||||
GameMode::MNA => ManiaStars::new(self).mods(mods).strains(),
|
GameMode::MNA => Strains::Mania(ManiaStars::new(self).mods(mods).strains()),
|
||||||
GameMode::TKO => TaikoStars::new(self).mods(mods).strains(),
|
GameMode::TKO => Strains::Taiko(TaikoStars::new(self).mods(mods).strains()),
|
||||||
GameMode::CTB => CatchStars::new(self).mods(mods).strains(),
|
GameMode::CTB => Strains::Catch(CatchStars::new(self).mods(mods).strains()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,24 +306,52 @@ impl BeatmapExt for Beatmap {
|
|||||||
|
|
||||||
/// The result of calculating the strains on a map.
|
/// The result of calculating the strains on a map.
|
||||||
/// Suitable to plot the difficulty of a map over time.
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Strains {
|
pub enum Strains {
|
||||||
|
/// osu!catch strain values.
|
||||||
|
Catch(catch::CatchStrains),
|
||||||
|
/// osu!mania strain values.
|
||||||
|
Mania(mania::ManiaStrains),
|
||||||
|
/// osu!standard strain values.
|
||||||
|
Osu(osu::OsuStrains),
|
||||||
|
/// osu!taiko strain values.
|
||||||
|
Taiko(taiko::TaikoStrains),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Strains {
|
||||||
/// Time in ms inbetween two strains.
|
/// Time in ms inbetween two strains.
|
||||||
pub section_length: f64,
|
#[inline]
|
||||||
/// Summed strains for each skill of the map's mode.
|
pub fn section_len(&self) -> f64 {
|
||||||
pub strains: Vec<f64>,
|
match self {
|
||||||
|
Strains::Catch(strains) => strains.section_len,
|
||||||
|
Strains::Mania(strains) => strains.section_len,
|
||||||
|
Strains::Osu(strains) => strains.section_len,
|
||||||
|
Strains::Taiko(strains) => strains.section_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of strain peaks per skill.
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Strains::Catch(strains) => strains.len(),
|
||||||
|
Strains::Mania(strains) => strains.len(),
|
||||||
|
Strains::Osu(strains) => strains.len(),
|
||||||
|
Strains::Taiko(strains) => strains.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a difficulty calculation based on the mode.
|
/// The result of a difficulty calculation based on the mode.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum DifficultyAttributes {
|
pub enum DifficultyAttributes {
|
||||||
/// osu!catch difficulty calculation reseult.
|
/// osu!catch difficulty calculation result.
|
||||||
Catch(catch::CatchDifficultyAttributes),
|
Catch(catch::CatchDifficultyAttributes),
|
||||||
/// osu!mania difficulty calculation reseult.
|
/// osu!mania difficulty calculation result.
|
||||||
Mania(mania::ManiaDifficultyAttributes),
|
Mania(mania::ManiaDifficultyAttributes),
|
||||||
/// osu!standard difficulty calculation reseult.
|
/// osu!standard difficulty calculation result.
|
||||||
Osu(osu::OsuDifficultyAttributes),
|
Osu(osu::OsuDifficultyAttributes),
|
||||||
/// osu!taiko difficulty calculation reseult.
|
/// osu!taiko difficulty calculation result.
|
||||||
Taiko(taiko::TaikoDifficultyAttributes),
|
Taiko(taiko::TaikoDifficultyAttributes),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,6 +471,7 @@ impl PerformanceAttributes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<PerformanceAttributes> for DifficultyAttributes {
|
impl From<PerformanceAttributes> for DifficultyAttributes {
|
||||||
|
#[inline]
|
||||||
fn from(attributes: PerformanceAttributes) -> Self {
|
fn from(attributes: PerformanceAttributes) -> Self {
|
||||||
match attributes {
|
match attributes {
|
||||||
PerformanceAttributes::Catch(attributes) => Self::Catch(attributes.difficulty),
|
PerformanceAttributes::Catch(attributes) => Self::Catch(attributes.difficulty),
|
||||||
|
|||||||
+22
-4
@@ -10,7 +10,7 @@ pub use gradual_performance::*;
|
|||||||
pub use pp::*;
|
pub use pp::*;
|
||||||
use strain::Strain;
|
use strain::Strain;
|
||||||
|
|
||||||
use crate::{parse::HitObject, Beatmap, GameMode, Mods, OsuStars, Strains};
|
use crate::{parse::HitObject, Beatmap, GameMode, Mods, OsuStars};
|
||||||
|
|
||||||
const SECTION_LEN: f64 = 400.0;
|
const SECTION_LEN: f64 = 400.0;
|
||||||
const STAR_SCALING_FACTOR: f64 = 0.018;
|
const STAR_SCALING_FACTOR: f64 = 0.018;
|
||||||
@@ -99,17 +99,35 @@ impl<'map> ManiaStars<'map> {
|
|||||||
///
|
///
|
||||||
/// Suitable to plot the difficulty of a map over time.
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn strains(self) -> Strains {
|
pub fn strains(self) -> ManiaStrains {
|
||||||
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
||||||
let strain = calculate_strain(self);
|
let strain = calculate_strain(self);
|
||||||
|
|
||||||
Strains {
|
ManiaStrains {
|
||||||
section_length: SECTION_LEN * clock_rate,
|
section_len: SECTION_LEN * clock_rate,
|
||||||
strains: strain.strain_peaks,
|
strains: strain.strain_peaks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of calculating the strains on a osu!taiko map.
|
||||||
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ManiaStrains {
|
||||||
|
/// Time in ms inbetween two strains.
|
||||||
|
pub section_len: f64,
|
||||||
|
/// Strain peaks of the strain skill.
|
||||||
|
pub strains: Vec<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ManiaStrains {
|
||||||
|
/// Returns the number of strain peaks per skill.
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.strains.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn calculate_strain(params: ManiaStars<'_>) -> Strain {
|
fn calculate_strain(params: ManiaStars<'_>) -> Strain {
|
||||||
let ManiaStars {
|
let ManiaStars {
|
||||||
map,
|
map,
|
||||||
|
|||||||
+41
-26
@@ -20,7 +20,7 @@ use skill::Skill;
|
|||||||
use skill_kind::SkillKind;
|
use skill_kind::SkillKind;
|
||||||
use slider_state::SliderState;
|
use slider_state::SliderState;
|
||||||
|
|
||||||
use crate::{curve::CurveBuffers, AnyStars, Beatmap, GameMode, Mods, Strains};
|
use crate::{curve::CurveBuffers, AnyStars, Beatmap, GameMode, Mods};
|
||||||
|
|
||||||
use self::skill::Skills;
|
use self::skill::Skills;
|
||||||
|
|
||||||
@@ -173,39 +173,54 @@ impl<'map> OsuStars<'map> {
|
|||||||
///
|
///
|
||||||
/// Suitable to plot the difficulty of a map over time.
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn strains(self) -> Strains {
|
pub fn strains(self) -> OsuStrains {
|
||||||
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
||||||
let (mut skills, _) = calculate_skills(self);
|
let (mut skills, _) = calculate_skills(self);
|
||||||
|
|
||||||
let mut aim = mem::take(&mut skills.aim().strain_peaks);
|
let len = skills.aim().strain_peaks.len();
|
||||||
let tuple = skills.speed_flashlight();
|
let (speed, flashlight) = skills.speed_flashlight();
|
||||||
|
|
||||||
let strains = match tuple {
|
let speed = speed.map_or_else(
|
||||||
(Some(speed), Some(flashlight)) => {
|
|| vec![0.0; len],
|
||||||
for ((aim, speed), flashlight) in aim
|
|skill| mem::take(&mut skill.strain_peaks),
|
||||||
.iter_mut()
|
);
|
||||||
.zip(&speed.strain_peaks)
|
|
||||||
.zip(&flashlight.strain_peaks)
|
|
||||||
{
|
|
||||||
*aim += speed + flashlight;
|
|
||||||
}
|
|
||||||
|
|
||||||
aim
|
let flashlight = flashlight.map_or_else(
|
||||||
}
|
|| vec![0.0; len],
|
||||||
(Some(strains), None) | (None, Some(strains)) => {
|
|skill| mem::take(&mut skill.strain_peaks),
|
||||||
for (aim, strain) in aim.iter_mut().zip(&strains.strain_peaks) {
|
);
|
||||||
*aim += strain;
|
|
||||||
}
|
|
||||||
|
|
||||||
aim
|
OsuStrains {
|
||||||
|
section_len: SECTION_LEN * clock_rate,
|
||||||
|
aim: mem::take(&mut skills.aim().strain_peaks),
|
||||||
|
aim_no_sliders: mem::take(&mut skills.aim_no_sliders().strain_peaks),
|
||||||
|
speed,
|
||||||
|
flashlight,
|
||||||
}
|
}
|
||||||
(None, None) => aim,
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Strains {
|
/// The result of calculating the strains on a osu!taiko map.
|
||||||
section_length: SECTION_LEN * clock_rate,
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
strains,
|
#[derive(Clone, Debug)]
|
||||||
}
|
pub struct OsuStrains {
|
||||||
|
/// Time in ms inbetween two strains.
|
||||||
|
pub section_len: f64,
|
||||||
|
/// Strain peaks of the aim skill.
|
||||||
|
pub aim: Vec<f64>,
|
||||||
|
/// Strain peaks of the aim skill without sliders.
|
||||||
|
pub aim_no_sliders: Vec<f64>,
|
||||||
|
/// Strain peaks of the speed skill.
|
||||||
|
pub speed: Vec<f64>,
|
||||||
|
/// Strain peaks of the flashlight skill.
|
||||||
|
pub flashlight: Vec<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OsuStrains {
|
||||||
|
/// Returns the number of strain peaks per skill.
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.aim.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -45,6 +45,7 @@ impl<'map> AnyStars<'map> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If the map is an osu!standard map, convert it to another mode.
|
/// If the map is an osu!standard map, convert it to another mode.
|
||||||
|
#[inline]
|
||||||
pub fn mode(self, mode: GameMode) -> Self {
|
pub fn mode(self, mode: GameMode) -> Self {
|
||||||
match self {
|
match self {
|
||||||
AnyStars::Osu(o) => match mode {
|
AnyStars::Osu(o) => match mode {
|
||||||
@@ -117,10 +118,10 @@ impl<'map> AnyStars<'map> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn strains(self) -> Strains {
|
pub fn strains(self) -> Strains {
|
||||||
match self {
|
match self {
|
||||||
Self::Catch(f) => f.strains(),
|
Self::Catch(f) => Strains::Catch(f.strains()),
|
||||||
Self::Mania(m) => m.strains(),
|
Self::Mania(m) => Strains::Mania(m.strains()),
|
||||||
Self::Osu(o) => o.strains(),
|
Self::Osu(o) => Strains::Osu(o.strains()),
|
||||||
Self::Taiko(t) => t.strains(),
|
Self::Taiko(t) => Strains::Taiko(t.strains()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-17
@@ -20,7 +20,7 @@ use stamina_cheese::StaminaCheeseDetector;
|
|||||||
use taiko_object::IntoTaikoObjectIter;
|
use taiko_object::IntoTaikoObjectIter;
|
||||||
|
|
||||||
use crate::taiko::skill::Skills;
|
use crate::taiko::skill::Skills;
|
||||||
use crate::{Beatmap, GameMode, Mods, OsuStars, Strains};
|
use crate::{Beatmap, GameMode, Mods, OsuStars};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@@ -137,29 +137,44 @@ impl<'map> TaikoStars<'map> {
|
|||||||
///
|
///
|
||||||
/// Suitable to plot the difficulty of a map over time.
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn strains(self) -> Strains {
|
pub fn strains(self) -> TaikoStrains {
|
||||||
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
let clock_rate = self.clock_rate.unwrap_or_else(|| self.mods.clock_rate());
|
||||||
let (skills, _) = calculate_skills(self);
|
let (skills, _) = calculate_skills(self);
|
||||||
|
|
||||||
let strains = skills
|
TaikoStrains {
|
||||||
.color
|
section_len: SECTION_LEN * clock_rate,
|
||||||
.strain_peaks
|
color: skills.color.strain_peaks,
|
||||||
.iter()
|
rhythm: skills.rhythm.strain_peaks,
|
||||||
.zip(skills.rhythm.strain_peaks.iter())
|
stamina_right: skills.stamina_right.strain_peaks,
|
||||||
.zip(skills.stamina_right.strain_peaks.iter())
|
stamina_left: skills.stamina_left.strain_peaks,
|
||||||
.zip(skills.stamina_left.strain_peaks.iter())
|
|
||||||
.map(|(((color, rhythm), stamina_right), stamina_left)| {
|
|
||||||
color + rhythm + stamina_right + stamina_left
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Strains {
|
|
||||||
section_length: SECTION_LEN * clock_rate,
|
|
||||||
strains,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of calculating the strains on a osu!taiko map.
|
||||||
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TaikoStrains {
|
||||||
|
/// Time in ms inbetween two strains.
|
||||||
|
pub section_len: f64,
|
||||||
|
/// Strain peaks of the color skill.
|
||||||
|
pub color: Vec<f64>,
|
||||||
|
/// Strain peaks of the rhythm skill.
|
||||||
|
pub rhythm: Vec<f64>,
|
||||||
|
/// Strain peaks of the left-stamina skill.
|
||||||
|
pub stamina_right: Vec<f64>,
|
||||||
|
/// Strain peaks of the right-stamina skill.
|
||||||
|
pub stamina_left: Vec<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaikoStrains {
|
||||||
|
/// Returns the number of strain peaks per skill.
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.color.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn calculate_skills(params: TaikoStars<'_>) -> (Skills, usize) {
|
fn calculate_skills(params: TaikoStars<'_>) -> (Skills, usize) {
|
||||||
let TaikoStars {
|
let TaikoStars {
|
||||||
map,
|
map,
|
||||||
|
|||||||
Reference in New Issue
Block a user