restructure Difficulty and ModeDifficulty

This commit is contained in:
MaxOhn
2024-03-03 09:57:44 +01:00
parent 3705338d12
commit e749a791fc
39 changed files with 446 additions and 448 deletions
+10 -7
View File
@@ -27,9 +27,9 @@ News posts of the latest gamemode updates:
let map = rosu_pp::Beatmap::from_path("./resources/2785319.osu").unwrap(); let map = rosu_pp::Beatmap::from_path("./resources/2785319.osu").unwrap();
// Calculate difficulty attributes // Calculate difficulty attributes
let diff_attrs = map.difficulty() let diff_attrs = rosu_pp::Difficulty::new()
.mods(8 + 16) // HDHR .mods(8 + 16) // HDHR
.calculate(); .calculate(&map);
let stars = diff_attrs.stars(); let stars = diff_attrs.stars();
@@ -63,17 +63,20 @@ println!("Stars: {stars} | PP: {pp}/{max_pp}");
Gradually calculating attributes provides an efficient way to process each hitobject Gradually calculating attributes provides an efficient way to process each hitobject
separately and calculate the attributes only up to that point. separately and calculate the attributes only up to that point.
For difficulty attributes, there is [`GradualDifficulty`] which implements [`Iterator`] For difficulty attributes, there is `GradualDifficulty` which implements `Iterator`
and for performance attributes there is [`GradualPerformance`] which requires the current and for performance attributes there is `GradualPerformance` which requires the current
score state. score state.
```rust ```rust
use rosu_pp::{Beatmap, GradualPerformance, ModeDifficulty, any::ScoreState}; use rosu_pp::{Beatmap, GradualPerformance, Difficulty, any::ScoreState};
let map = Beatmap::from_path("./resources/1028484.osu").unwrap(); let map = Beatmap::from_path("./resources/1028484.osu").unwrap();
let difficulty = ModeDifficulty::new().mods(16 + 64).clock_rate(1.2); // HRDT on 1.2x
let mut gradual = GradualPerformance::new(&difficulty, &map); let mut gradual = Difficulty::new()
.mods(16 + 64) // HRDT
.clock_rate(1.2)
.gradual_performance(&map);
let mut state = ScoreState::new(); // empty state, everything is on 0. let mut state = ScoreState::new(); // empty state, everything is on 0.
// The first 10 hitresults are 300s // The first 10 hitresults are 300s
+133
View File
@@ -0,0 +1,133 @@
use std::{
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
};
use crate::{
model::{beatmap::Converted, mode::IGameMode},
util::generic_fmt::GenericFormatter,
Difficulty,
};
/// Difficulty calculator on maps of a given mode.
#[must_use]
pub struct ConvertedDifficulty<M> {
inner: Difficulty,
_mode: PhantomData<M>,
}
impl<M> ConvertedDifficulty<M> {
/// Create a new difficulty calculator for a generic mode.
pub const fn new() -> Self {
Self::from_difficulty(Difficulty::new())
}
pub(crate) const fn from_difficulty(difficulty: Difficulty) -> Self {
Self {
inner: difficulty,
_mode: PhantomData,
}
}
/// Return the internal [`Difficulty`].
pub const fn into_inner(self) -> Difficulty {
self.inner
}
/// Cast from generic mode `M` to `N`.
pub fn cast<N: IGameMode>(self) -> ConvertedDifficulty<N> {
ConvertedDifficulty {
inner: self.inner,
_mode: PhantomData,
}
}
/// Specify mods through their bit values.
///
/// See [https://github.com/ppy/osu-api/wiki#mods](https://github.com/ppy/osu-api/wiki#mods)
pub const fn mods(self, mods: u32) -> Self {
Self {
inner: self.inner.mods(mods),
..self
}
}
/// Amount of passed objects for partial plays, e.g. a fail.
pub const fn passed_objects(self, passed_objects: u32) -> Self {
Self {
inner: self.inner.passed_objects(passed_objects),
..self
}
}
/// Adjust the clock rate used in the calculation between 0.01 and 100.0.
///
/// If none is specified, it will take the clock rate based on the mods
/// i.e. 1.5 for DT, 0.75 for HT and 1.0 otherwise.
pub fn clock_rate(self, clock_rate: f64) -> Self {
Self {
inner: self.inner.clock_rate(clock_rate),
..self
}
}
}
impl<M: IGameMode> ConvertedDifficulty<M> {
/// Perform the difficulty calculation for a [`Converted`] beatmap and
/// process the final skill values.
pub fn calculate(&self, map: &Converted<'_, M>) -> M::DifficultyAttributes {
M::difficulty(&self.inner, map)
}
/// Perform a difficulty calculation for a [`Converted`] beatmap without
/// processing the final skill values.
pub fn strains(&self, map: &Converted<'_, M>) -> M::Strains {
M::strains(&self.inner, map)
}
/// Create a gradual difficulty calculator for a [`Converted`] beatmap.
pub fn gradual_difficulty(&self, map: &Converted<'_, M>) -> M::GradualDifficulty {
M::gradual_difficulty(&self.inner, map)
}
/// Create a gradual performance calculator for a [`Converted`] beatmap.
pub fn gradual_performance(&self, map: &Converted<'_, M>) -> M::GradualPerformance {
M::gradual_performance(&self.inner, map)
}
}
impl<M: IGameMode> From<Difficulty> for ConvertedDifficulty<M> {
fn from(difficulty: Difficulty) -> Self {
Self::from_difficulty(difficulty)
}
}
impl<M> AsRef<Difficulty> for ConvertedDifficulty<M> {
fn as_ref(&self) -> &Difficulty {
&self.inner
}
}
impl<M> Clone for ConvertedDifficulty<M> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_mode: PhantomData,
}
}
}
impl<M> Debug for ConvertedDifficulty<M> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("ConvertedDifficulty")
.field("inner", &self.inner)
.field("mode", &GenericFormatter::<M>::new())
.finish()
}
}
impl<M> PartialEq for ConvertedDifficulty<M> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
+21 -14
View File
@@ -4,11 +4,12 @@ use rosu_map::section::general::GameMode;
use crate::{ use crate::{
any::DifficultyAttributes, any::DifficultyAttributes,
catch::{CatchBeatmap, CatchGradualDifficulty}, catch::{Catch, CatchBeatmap, CatchGradualDifficulty},
mania::{ManiaBeatmap, ManiaGradualDifficulty}, mania::{Mania, ManiaBeatmap, ManiaGradualDifficulty},
osu::{OsuBeatmap, OsuGradualDifficulty}, model::mode::IGameMode,
taiko::{TaikoBeatmap, TaikoGradualDifficulty}, osu::{Osu, OsuBeatmap, OsuGradualDifficulty},
Beatmap, ModeDifficulty, taiko::{Taiko, TaikoBeatmap, TaikoGradualDifficulty},
Beatmap, Converted, Difficulty,
}; };
/// Gradually calculate the difficulty attributes on maps of any mode. /// Gradually calculate the difficulty attributes on maps of any mode.
@@ -22,10 +23,10 @@ use crate::{
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, GradualDifficulty, ModeDifficulty}; /// use rosu_pp::{Beatmap, GradualDifficulty, Difficulty};
/// ///
/// let map = Beatmap::from_path("./resources/2785319.osu").unwrap(); /// let map = Beatmap::from_path("./resources/2785319.osu").unwrap();
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut iter = GradualDifficulty::new(&difficulty, &map); /// let mut iter = GradualDifficulty::new(&difficulty, &map);
/// ///
/// // the difficulty of the map after the first object /// // the difficulty of the map after the first object
@@ -53,22 +54,28 @@ pub enum GradualDifficulty {
macro_rules! from_converted { macro_rules! from_converted {
( $fn:ident, $mode:ident, $converted:ident ) => { ( $fn:ident, $mode:ident, $converted:ident ) => {
#[doc = concat!("Create a [`GradualDifficulty`] for a [`", stringify!($converted), "`]")] #[doc = concat!("Create a [`GradualDifficulty`] for a [`", stringify!($converted), "`]")]
pub fn $fn(difficulty: &ModeDifficulty, converted: &$converted<'_>) -> Self { pub fn $fn(difficulty: &Difficulty, converted: &$converted<'_>) -> Self {
Self::$mode(difficulty.gradual_difficulty(converted)) Self::$mode($mode::gradual_difficulty(difficulty, converted))
} }
}; };
} }
impl GradualDifficulty { impl GradualDifficulty {
/// Create a [`GradualDifficulty`] for a map of any mode. /// Create a [`GradualDifficulty`] for a map of any mode.
pub fn new(difficulty: &ModeDifficulty, map: &Beatmap) -> Self { pub fn new(difficulty: &Difficulty, map: &Beatmap) -> Self {
let map = Cow::Borrowed(map); let map = Cow::Borrowed(map);
match map.mode { match map.mode {
GameMode::Osu => Self::Osu(difficulty.gradual_difficulty(&OsuBeatmap::new(map))), GameMode::Osu => Self::Osu(Osu::gradual_difficulty(difficulty, &Converted::new(map))),
GameMode::Taiko => Self::Taiko(difficulty.gradual_difficulty(&TaikoBeatmap::new(map))), GameMode::Taiko => {
GameMode::Catch => Self::Catch(difficulty.gradual_difficulty(&CatchBeatmap::new(map))), Self::Taiko(Taiko::gradual_difficulty(difficulty, &Converted::new(map)))
GameMode::Mania => Self::Mania(difficulty.gradual_difficulty(&ManiaBeatmap::new(map))), }
GameMode::Catch => {
Self::Catch(Catch::gradual_difficulty(difficulty, &Converted::new(map)))
}
GameMode::Mania => {
Self::Mania(Mania::gradual_difficulty(difficulty, &Converted::new(map)))
}
} }
} }
+70 -113
View File
@@ -3,144 +3,79 @@ use std::borrow::Cow;
use rosu_map::section::general::GameMode; use rosu_map::section::general::GameMode;
use crate::{ use crate::{
catch::{Catch, CatchBeatmap}, catch::Catch,
mania::{Mania, ManiaBeatmap}, mania::Mania,
model::beatmap::{Beatmap, Converted}, model::beatmap::{Beatmap, Converted},
osu::{Osu, OsuBeatmap}, osu::Osu,
taiko::{Taiko, TaikoBeatmap}, taiko::Taiko,
GradualDifficulty, GradualPerformance,
}; };
use self::mode::ModeDifficulty; use self::converted::ConvertedDifficulty;
use super::{attributes::DifficultyAttributes, Strains}; use super::{attributes::DifficultyAttributes, Strains};
pub mod converted;
pub mod gradual; pub mod gradual;
pub mod mode;
pub mod object; pub mod object;
pub mod skills; pub mod skills;
use crate::{model::mode::IGameMode, util::mods::Mods};
/// Difficulty calculator on maps of any mode. /// Difficulty calculator on maps of any mode.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
#[must_use] #[must_use]
pub struct Difficulty<'map> { pub struct Difficulty {
map: Cow<'map, Beatmap>, mods: u32,
inner: ModeDifficulty, passed_objects: Option<u32>,
clock_rate: Option<f64>,
} }
impl<'map> Difficulty<'map> { impl Difficulty {
/// Create a new difficulty calculator for the given beatmap. /// Create a new difficulty calculator.
pub const fn new(map: &'map Beatmap) -> Self { pub const fn new() -> Self {
Self::new_with_cow(Cow::Borrowed(map))
}
const fn new_with_cow(map: Cow<'map, Beatmap>) -> Self {
Self { Self {
map, mods: 0,
inner: ModeDifficulty::new(), passed_objects: None,
clock_rate: None,
} }
} }
}
macro_rules! impl_from_mode { /// Use this [`&Difficulty`] as a calculator for a specific [`IGameMode`].
( $mode:ident ) => {
impl<'a> From<Converted<'a, $mode>> for Difficulty<'a> {
fn from(converted: Converted<'a, $mode>) -> Self {
Self::new_with_cow(converted.into_inner())
}
}
impl<'a, 'b: 'a> From<&'b Converted<'a, $mode>> for Difficulty<'a> {
fn from(converted: &'b Converted<'a, $mode>) -> Self {
Self::new(&converted)
}
}
};
}
impl_from_mode!(Osu);
impl_from_mode!(Taiko);
impl_from_mode!(Catch);
impl_from_mode!(Mania);
impl Difficulty<'_> {
/// Attempt to convert the map to the specified mode.
/// ///
/// If the conversion is incompatible, `None` is returned. /// [`&Difficulty`]: Difficulty
/// pub const fn with_mode<M: IGameMode>(&self) -> ConvertedDifficulty<M> {
/// If the given mode should be ignored in case it is incompatible, use let this = Self {
/// [`mode_or_ignore`] instead. mods: self.mods,
/// passed_objects: self.passed_objects,
/// [`mode_or_ignore`]: Self::mode_or_ignore clock_rate: self.clock_rate,
pub fn try_mode(&mut self, mode: GameMode) -> Option<&mut Self> {
let map = match mode {
GameMode::Osu => OsuBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
GameMode::Taiko => TaikoBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
GameMode::Catch => CatchBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
GameMode::Mania => ManiaBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
}; };
if matches!(map, Cow::Owned(_)) { ConvertedDifficulty::from_difficulty(this)
let map = map.into_owned();
self.map = Cow::Owned(map);
}
Some(self)
}
/// Attempt to convert the map to the specified mode.
///
/// If the conversion is incompatible, the map won't be modified.
///
/// To see whether the given mode is incompatible, use [`try_mode`]
/// instead.
///
/// [`try_mode`]: Self::try_mode
pub fn mode_or_ignore(&mut self, mode: GameMode) -> &mut Self {
let map = self.map.as_ref();
let map_opt = match mode {
GameMode::Osu => OsuBeatmap::try_from_ref(map).map(Converted::into_inner),
GameMode::Taiko => TaikoBeatmap::try_from_ref(map).map(Converted::into_inner),
GameMode::Catch => CatchBeatmap::try_from_ref(map).map(Converted::into_inner),
GameMode::Mania => ManiaBeatmap::try_from_ref(map).map(Converted::into_inner),
};
match map_opt {
Some(cow @ Cow::Owned(_)) => {
let map = cow.into_owned();
self.map = Cow::Owned(map);
}
Some(Cow::Borrowed(_)) | None => {}
}
self
} }
/// Specify mods through their bit values. /// Specify mods through their bit values.
/// ///
/// See [https://github.com/ppy/osu-api/wiki#mods](https://github.com/ppy/osu-api/wiki#mods) /// See [https://github.com/ppy/osu-api/wiki#mods](https://github.com/ppy/osu-api/wiki#mods)
pub fn mods(self, mods: u32) -> Self { pub const fn mods(self, mods: u32) -> Self {
Self { Self { mods, ..self }
inner: self.inner.mods(mods),
..self
}
} }
/// Amount of passed objects for partial plays, e.g. a fail. /// Amount of passed objects for partial plays, e.g. a fail.
pub fn passed_objects(self, passed_objects: u32) -> Self { pub const fn passed_objects(self, passed_objects: u32) -> Self {
Self { Self {
inner: self.inner.passed_objects(passed_objects), passed_objects: Some(passed_objects),
..self ..self
} }
} }
/// Adjust the clock rate used in the calculation. /// Adjust the clock rate used in the calculation between 0.01 and 100.0.
/// ///
/// If none is specified, it will take the clock rate based on the mods /// If none is specified, it will take the clock rate based on the mods
/// i.e. 1.5 for DT, 0.75 for HT and 1.0 otherwise. /// i.e. 1.5 for DT, 0.75 for HT and 1.0 otherwise.
pub fn clock_rate(self, clock_rate: f64) -> Self { pub fn clock_rate(self, clock_rate: f64) -> Self {
Self { Self {
inner: self.inner.clock_rate(clock_rate), clock_rate: Some(clock_rate.clamp(0.01, 100.0)),
..self ..self
} }
} }
@@ -148,19 +83,19 @@ impl Difficulty<'_> {
/// Perform the difficulty calculation. /// Perform the difficulty calculation.
/// ///
/// The returned attributes depend on the map's mode. /// The returned attributes depend on the map's mode.
pub fn calculate(&self) -> DifficultyAttributes { pub fn calculate(&self, map: &Beatmap) -> DifficultyAttributes {
let map = Cow::Borrowed(self.map.as_ref()); let map = Cow::Borrowed(map);
match self.map.mode { match map.mode {
GameMode::Osu => DifficultyAttributes::Osu(self.inner.calculate(&OsuBeatmap::new(map))), GameMode::Osu => DifficultyAttributes::Osu(Osu::difficulty(self, &Converted::new(map))),
GameMode::Taiko => { GameMode::Taiko => {
DifficultyAttributes::Taiko(self.inner.calculate(&TaikoBeatmap::new(map))) DifficultyAttributes::Taiko(Taiko::difficulty(self, &Converted::new(map)))
} }
GameMode::Catch => { GameMode::Catch => {
DifficultyAttributes::Catch(self.inner.calculate(&CatchBeatmap::new(map))) DifficultyAttributes::Catch(Catch::difficulty(self, &Converted::new(map)))
} }
GameMode::Mania => { GameMode::Mania => {
DifficultyAttributes::Mania(self.inner.calculate(&ManiaBeatmap::new(map))) DifficultyAttributes::Mania(Mania::difficulty(self, &Converted::new(map)))
} }
} }
} }
@@ -169,14 +104,36 @@ impl Difficulty<'_> {
/// strains, return them as is. /// strains, return them as is.
/// ///
/// Suitable to plot the difficulty of a map over time. /// Suitable to plot the difficulty of a map over time.
pub fn strains(&self) -> Strains { pub fn strains(&self, map: &Beatmap) -> Strains {
let map = Cow::Borrowed(self.map.as_ref()); let map = Cow::Borrowed(map);
match self.map.mode { match map.mode {
GameMode::Osu => Strains::Osu(self.inner.strains(&OsuBeatmap::new(map))), GameMode::Osu => Strains::Osu(Osu::strains(self, &Converted::new(map))),
GameMode::Taiko => Strains::Taiko(self.inner.strains(&TaikoBeatmap::new(map))), GameMode::Taiko => Strains::Taiko(Taiko::strains(self, &Converted::new(map))),
GameMode::Catch => Strains::Catch(self.inner.strains(&CatchBeatmap::new(map))), GameMode::Catch => Strains::Catch(Catch::strains(self, &Converted::new(map))),
GameMode::Mania => Strains::Mania(self.inner.strains(&ManiaBeatmap::new(map))), GameMode::Mania => Strains::Mania(Mania::strains(self, &Converted::new(map))),
} }
} }
/// Create a gradual difficulty calculator for a [`Beatmap`].
pub fn gradual_difficulty(&self, map: &Beatmap) -> GradualDifficulty {
GradualDifficulty::new(self, map)
}
/// Create a gradual performance calculator for a [`Beatmap`].
pub fn gradual_performance(&self, map: &Beatmap) -> GradualPerformance {
GradualPerformance::new(self, map)
}
pub(crate) const fn get_mods(&self) -> u32 {
self.mods
}
pub(crate) fn get_clock_rate(&self) -> f64 {
self.clock_rate.unwrap_or_else(|| self.mods.clock_rate())
}
pub(crate) fn get_passed_objects(&self) -> usize {
self.passed_objects.map_or(usize::MAX, |n| n as usize)
}
} }
-87
View File
@@ -1,87 +0,0 @@
use crate::{
model::{beatmap::Converted, mode::IGameMode},
util::mods::Mods,
};
/// Difficulty calculator on maps of a given mode.
#[derive(Clone, Debug, Default, PartialEq)]
#[must_use]
pub struct ModeDifficulty {
mods: u32,
passed_objects: Option<u32>,
clock_rate: Option<f64>,
}
impl ModeDifficulty {
/// Create a new difficulty calculator.
pub const fn new() -> Self {
Self {
mods: 0,
passed_objects: None,
clock_rate: None,
}
}
/// Specify mods through their bit values.
///
/// See [https://github.com/ppy/osu-api/wiki#mods](https://github.com/ppy/osu-api/wiki#mods)
pub const fn mods(self, mods: u32) -> Self {
Self { mods, ..self }
}
/// Amount of passed objects for partial plays, e.g. a fail.
pub const fn passed_objects(self, passed_objects: u32) -> Self {
Self {
passed_objects: Some(passed_objects),
..self
}
}
/// Adjust the clock rate used in the calculation between 0.01 and 100.0.
///
/// If none is specified, it will take the clock rate based on the mods
/// i.e. 1.5 for DT, 0.75 for HT and 1.0 otherwise.
pub fn clock_rate(self, clock_rate: f64) -> Self {
Self {
clock_rate: Some(clock_rate.clamp(0.01, 100.0)),
..self
}
}
/// Perform the difficulty calculation for a [`Converted`] beatmap and
/// process the final skill values.
pub fn calculate<M: IGameMode>(&self, map: &Converted<'_, M>) -> M::DifficultyAttributes {
M::difficulty(self, map)
}
/// Perform a difficulty calculation for a [`Converted`] beatmap without
/// processing the final skill values.
pub fn strains<M: IGameMode>(&self, map: &Converted<'_, M>) -> M::Strains {
M::strains(self, map)
}
/// Create a gradual difficulty calculator for a [`Converted`] beatmap.
pub fn gradual_difficulty<M: IGameMode>(&self, map: &Converted<'_, M>) -> M::GradualDifficulty {
M::gradual_difficulty(self, map)
}
/// Create a gradual performance calculator for a [`Converted`] beatmap.
pub fn gradual_performance<M: IGameMode>(
&self,
map: &Converted<'_, M>,
) -> M::GradualPerformance {
M::gradual_performance(self, map)
}
pub(crate) const fn get_mods(&self) -> u32 {
self.mods
}
pub(crate) fn get_clock_rate(&self) -> f64 {
self.clock_rate.unwrap_or_else(|| self.mods.clock_rate())
}
pub(crate) fn get_passed_objects(&self) -> usize {
self.passed_objects.map_or(usize::MAX, |n| n as usize)
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ pub use self::{
attributes::{ attributes::{
AttributeProvider, DifficultyAttributes, ModeAttributeProvider, PerformanceAttributes, AttributeProvider, DifficultyAttributes, ModeAttributeProvider, PerformanceAttributes,
}, },
difficulty::{gradual::GradualDifficulty, mode::ModeDifficulty, Difficulty}, difficulty::{converted::ConvertedDifficulty, gradual::GradualDifficulty, Difficulty},
performance::{gradual::GradualPerformance, HitResultPriority, Performance}, performance::{gradual::GradualPerformance, HitResultPriority, Performance},
score_state::ScoreState, score_state::ScoreState,
strains::Strains, strains::Strains,
+21 -14
View File
@@ -4,11 +4,12 @@ use rosu_map::section::general::GameMode;
use crate::{ use crate::{
any::{PerformanceAttributes, ScoreState}, any::{PerformanceAttributes, ScoreState},
catch::{CatchBeatmap, CatchGradualPerformance}, catch::{Catch, CatchBeatmap, CatchGradualPerformance},
mania::{ManiaBeatmap, ManiaGradualPerformance}, mania::{Mania, ManiaBeatmap, ManiaGradualPerformance},
osu::{OsuBeatmap, OsuGradualPerformance}, model::mode::IGameMode,
taiko::{TaikoBeatmap, TaikoGradualPerformance}, osu::{Osu, OsuBeatmap, OsuGradualPerformance},
Beatmap, ModeDifficulty, taiko::{Taiko, TaikoBeatmap, TaikoGradualPerformance},
Beatmap, Converted, Difficulty,
}; };
/// Gradually calculate the performance attributes on maps of any mode. /// Gradually calculate the performance attributes on maps of any mode.
@@ -31,10 +32,10 @@ use crate::{
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, GradualPerformance, ModeDifficulty, any::ScoreState}; /// use rosu_pp::{Beatmap, GradualPerformance, Difficulty, any::ScoreState};
/// ///
/// let map = Beatmap::from_path("./resources/2785319.osu").unwrap(); /// let map = Beatmap::from_path("./resources/2785319.osu").unwrap();
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut gradual = GradualPerformance::new(&difficulty, &map); /// let mut gradual = GradualPerformance::new(&difficulty, &map);
/// let mut state = ScoreState::new(); // empty state, everything is on 0. /// let mut state = ScoreState::new(); // empty state, everything is on 0.
/// ///
@@ -102,22 +103,28 @@ pub enum GradualPerformance {
macro_rules! from_converted { macro_rules! from_converted {
( $fn:ident, $mode:ident, $converted:ident ) => { ( $fn:ident, $mode:ident, $converted:ident ) => {
#[doc = concat!("Create a [`GradualPerformance`] for a [`", stringify!($converted), "`]")] #[doc = concat!("Create a [`GradualPerformance`] for a [`", stringify!($converted), "`]")]
pub fn $fn(difficulty: &ModeDifficulty, converted: &$converted<'_>) -> Self { pub fn $fn(difficulty: &Difficulty, converted: &$converted<'_>) -> Self {
Self::$mode(difficulty.gradual_performance(converted)) Self::$mode($mode::gradual_performance(difficulty, converted))
} }
}; };
} }
impl GradualPerformance { impl GradualPerformance {
/// Create a [`GradualPerformance`] for a map of any mode. /// Create a [`GradualPerformance`] for a map of any mode.
pub fn new(difficulty: &ModeDifficulty, map: &Beatmap) -> Self { pub fn new(difficulty: &Difficulty, map: &Beatmap) -> Self {
let map = Cow::Borrowed(map); let map = Cow::Borrowed(map);
match map.mode { match map.mode {
GameMode::Osu => Self::Osu(difficulty.gradual_performance(&OsuBeatmap::new(map))), GameMode::Osu => Self::Osu(Osu::gradual_performance(difficulty, &Converted::new(map))),
GameMode::Taiko => Self::Taiko(difficulty.gradual_performance(&TaikoBeatmap::new(map))), GameMode::Taiko => {
GameMode::Catch => Self::Catch(difficulty.gradual_performance(&CatchBeatmap::new(map))), Self::Taiko(Taiko::gradual_performance(difficulty, &Converted::new(map)))
GameMode::Mania => Self::Mania(difficulty.gradual_performance(&ManiaBeatmap::new(map))), }
GameMode::Catch => {
Self::Catch(Catch::gradual_performance(difficulty, &Converted::new(map)))
}
GameMode::Mania => {
Self::Mania(Mania::gradual_performance(difficulty, &Converted::new(map)))
}
} }
} }
+8 -8
View File
@@ -8,7 +8,7 @@ use crate::{
CatchBeatmap, CatchDifficultyAttributes, CatchBeatmap, CatchDifficultyAttributes,
}, },
util::mods::Mods, util::mods::Mods,
ModeDifficulty, Difficulty,
}; };
use super::{ use super::{
@@ -32,14 +32,14 @@ use super::{
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::catch::{Catch, CatchGradualDifficulty}; /// use rosu_pp::catch::{Catch, CatchGradualDifficulty};
/// ///
/// let converted = Beatmap::from_path("./resources/2118524.osu") /// let converted = Beatmap::from_path("./resources/2118524.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted::<Catch>(); /// .unchecked_into_converted::<Catch>();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut iter = CatchGradualDifficulty::new(&difficulty, &converted); /// let mut iter = CatchGradualDifficulty::new(&difficulty, &converted);
/// ///
/// // the difficulty of the map after the first hit object /// // the difficulty of the map after the first hit object
@@ -66,7 +66,7 @@ pub struct CatchGradualDifficulty {
} }
impl CatchGradualDifficulty { impl CatchGradualDifficulty {
pub fn new(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &CatchBeatmap<'_>) -> Self {
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
@@ -163,7 +163,7 @@ impl ExactSizeIterator for CatchGradualDifficulty {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::Beatmap; use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*; use super::*;
@@ -171,7 +171,7 @@ mod tests {
fn empty() { fn empty() {
let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted(); let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = CatchGradualDifficulty::new(&difficulty, &converted); let mut gradual = CatchGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none()); assert!(gradual.next().is_none());
@@ -183,7 +183,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted(); .unchecked_into_converted();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = CatchGradualDifficulty::new(&difficulty, &converted); let mut gradual = CatchGradualDifficulty::new(&difficulty, &converted);
let mut gradual_2nd = CatchGradualDifficulty::new(&difficulty, &converted); let mut gradual_2nd = CatchGradualDifficulty::new(&difficulty, &converted);
@@ -207,7 +207,7 @@ mod tests {
assert_eq!(next_gradual, next_gradual_3rd); assert_eq!(next_gradual, next_gradual_3rd);
} }
let expected = ModeDifficulty::new() let expected = ConvertedDifficulty::new()
.passed_objects(i as u32) .passed_objects(i as u32)
.calculate(&converted); .calculate(&converted);
+4 -4
View File
@@ -1,5 +1,5 @@
use crate::{ use crate::{
any::difficulty::{mode::ModeDifficulty, skills::Skill}, any::difficulty::{skills::Skill, Difficulty},
catch::{ catch::{
catcher::Catcher, convert::convert_objects, difficulty::object::CatchDifficultyObject, catcher::Catcher, convert::convert_objects, difficulty::object::CatchDifficultyObject,
}, },
@@ -22,7 +22,7 @@ mod skills;
const STAR_SCALING_FACTOR: f64 = 0.153; const STAR_SCALING_FACTOR: f64 = 0.153;
pub fn difficulty( pub fn difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
converted: &CatchBeatmap<'_>, converted: &CatchBeatmap<'_>,
) -> CatchDifficultyAttributes { ) -> CatchDifficultyAttributes {
let DifficultyValues { let DifficultyValues {
@@ -41,7 +41,7 @@ pub struct CatchDifficultySetup {
} }
impl CatchDifficultySetup { impl CatchDifficultySetup {
pub fn new(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &CatchBeatmap<'_>) -> Self {
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
@@ -67,7 +67,7 @@ pub struct DifficultyValues {
} }
impl DifficultyValues { impl DifficultyValues {
pub fn calculate(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> Self { pub fn calculate(difficulty: &Difficulty, converted: &CatchBeatmap<'_>) -> Self {
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
+5 -5
View File
@@ -1,9 +1,9 @@
use crate::{ use crate::{
any::ModeDifficulty,
model::{ model::{
beatmap::Beatmap, beatmap::Beatmap,
mode::{ConvertStatus, IGameMode}, mode::{ConvertStatus, IGameMode},
}, },
Difficulty,
}; };
pub use self::{ pub use self::{
@@ -47,13 +47,13 @@ impl IGameMode for Catch {
} }
fn difficulty( fn difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
converted: &CatchBeatmap<'_>, converted: &CatchBeatmap<'_>,
) -> Self::DifficultyAttributes { ) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted) difficulty::difficulty(difficulty, converted)
} }
fn strains(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> Self::Strains { fn strains(difficulty: &Difficulty, converted: &CatchBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted) strains::strains(difficulty, converted)
} }
@@ -62,14 +62,14 @@ impl IGameMode for Catch {
} }
fn gradual_difficulty( fn gradual_difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &CatchBeatmap<'_>, map: &CatchBeatmap<'_>,
) -> Self::GradualDifficulty { ) -> Self::GradualDifficulty {
CatchGradualDifficulty::new(difficulty, map) CatchGradualDifficulty::new(difficulty, map)
} }
fn gradual_performance( fn gradual_performance(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &CatchBeatmap<'_>, map: &CatchBeatmap<'_>,
) -> Self::GradualPerformance { ) -> Self::GradualPerformance {
CatchGradualPerformance::new(difficulty, map) CatchGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{ use crate::{
catch::{CatchBeatmap, CatchGradualDifficulty, CatchPerformanceAttributes, CatchScoreState}, catch::{CatchBeatmap, CatchGradualDifficulty, CatchPerformanceAttributes, CatchScoreState},
ModeDifficulty, Difficulty,
}; };
/// Gradually calculate the performance attributes of an osu!catch map. /// Gradually calculate the performance attributes of an osu!catch map.
@@ -21,14 +21,14 @@ use crate::{
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::catch::{Catch, CatchGradualPerformance, CatchScoreState}; /// use rosu_pp::catch::{Catch, CatchGradualPerformance, CatchScoreState};
/// ///
/// let converted = Beatmap::from_path("./resources/2118524.osu") /// let converted = Beatmap::from_path("./resources/2118524.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted::<Catch>(); /// .unchecked_into_converted::<Catch>();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut gradual = CatchGradualPerformance::new(&difficulty, &converted); /// let mut gradual = CatchGradualPerformance::new(&difficulty, &converted);
/// let mut state = CatchScoreState::new(); // empty state, everything is on 0. /// let mut state = CatchScoreState::new(); // empty state, everything is on 0.
/// ///
@@ -90,7 +90,7 @@ pub struct CatchGradualPerformance {
impl CatchGradualPerformance { impl CatchGradualPerformance {
/// Create a new gradual performance calculator for osu!catch maps. /// Create a new gradual performance calculator for osu!catch maps.
pub fn new(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &CatchBeatmap<'_>) -> Self {
let difficulty = CatchGradualDifficulty::new(difficulty, converted); let difficulty = CatchGradualDifficulty::new(difficulty, converted);
Self { difficulty } Self { difficulty }
@@ -144,7 +144,7 @@ mod tests {
.unchecked_into_converted(); .unchecked_into_converted();
let mods = 88; // HDHRDT let mods = 88; // HDHRDT
let difficulty = ModeDifficulty::new().mods(88); let difficulty = Difficulty::new().mods(88);
let mut gradual = CatchGradualPerformance::new(&difficulty, &converted); let mut gradual = CatchGradualPerformance::new(&difficulty, &converted);
let mut gradual_2nd = CatchGradualPerformance::new(&difficulty, &converted); let mut gradual_2nd = CatchGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -1,8 +1,7 @@
use std::cmp::{self, Ordering}; use std::cmp::{self, Ordering};
use crate::{ use crate::{
any::ModeAttributeProvider, any::{Difficulty, ModeAttributeProvider},
any::ModeDifficulty,
osu::OsuPerformance, osu::OsuPerformance,
util::{map_or_attrs::MapOrAttrs, mods::Mods}, util::{map_or_attrs::MapOrAttrs, mods::Mods},
}; };
@@ -21,7 +20,7 @@ pub mod gradual;
#[must_use] #[must_use]
pub struct CatchPerformance<'map> { pub struct CatchPerformance<'map> {
map_or_attrs: MapOrAttrs<'map, Catch>, map_or_attrs: MapOrAttrs<'map, Catch>,
difficulty: ModeDifficulty, difficulty: Difficulty,
acc: Option<f64>, acc: Option<f64>,
combo: Option<u32>, combo: Option<u32>,
fruits: Option<u32>, fruits: Option<u32>,
@@ -36,7 +35,7 @@ impl<'map> CatchPerformance<'map> {
pub const fn new(map: CatchBeatmap<'map>) -> Self { pub const fn new(map: CatchBeatmap<'map>) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Map(map), map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
acc: None, acc: None,
combo: None, combo: None,
fruits: None, fruits: None,
@@ -50,7 +49,7 @@ impl<'map> CatchPerformance<'map> {
pub(crate) const fn from_catch_attributes(attrs: CatchDifficultyAttributes) -> Self { pub(crate) const fn from_catch_attributes(attrs: CatchDifficultyAttributes) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Attrs(attrs), map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
acc: None, acc: None,
combo: None, combo: None,
fruits: None, fruits: None,
@@ -180,7 +179,7 @@ impl<'map> CatchPerformance<'map> {
pub fn generate_state(&mut self) -> CatchScoreState { pub fn generate_state(&mut self) -> CatchScoreState {
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => { MapOrAttrs::Map(ref map) => {
let attrs = self.generate_attributes(map); let attrs = self.difficulty.with_mode().calculate(map);
self.map_or_attrs.insert_attrs(attrs) self.map_or_attrs.insert_attrs(attrs)
} }
@@ -327,7 +326,7 @@ impl<'map> CatchPerformance<'map> {
let state = self.generate_state(); let state = self.generate_state();
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => self.generate_attributes(map), MapOrAttrs::Map(ref map) => self.difficulty.with_mode().calculate(map),
MapOrAttrs::Attrs(attrs) => attrs, MapOrAttrs::Attrs(attrs) => attrs,
}; };
@@ -340,10 +339,6 @@ impl<'map> CatchPerformance<'map> {
inner.calculate() inner.calculate()
} }
fn generate_attributes(&self, map: &CatchBeatmap<'_>) -> CatchDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`CatchPerformance`] through a [`ModeAttributeProvider`]. /// Try to create [`CatchPerformance`] through a [`ModeAttributeProvider`].
/// ///
/// If you already calculated the attributes for the current map-mod /// If you already calculated the attributes for the current map-mod
@@ -547,7 +542,7 @@ mod test {
use proptest::prelude::*; use proptest::prelude::*;
use crate::Beatmap; use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*; use super::*;
@@ -564,7 +559,7 @@ mod test {
.unwrap() .unwrap()
.unchecked_into_converted::<Catch>(); .unchecked_into_converted::<Catch>();
let attrs = ModeDifficulty::new().calculate(&converted); let attrs = ConvertedDifficulty::new().calculate(&converted);
assert_eq!(N_FRUITS, attrs.n_fruits); assert_eq!(N_FRUITS, attrs.n_fruits);
assert_eq!(N_DROPLETS, attrs.n_droplets); assert_eq!(N_DROPLETS, attrs.n_droplets);
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::{any::ModeDifficulty, catch::difficulty::DifficultyValues}; use crate::{any::Difficulty, catch::difficulty::DifficultyValues};
use super::convert::CatchBeatmap; use super::convert::CatchBeatmap;
@@ -16,7 +16,7 @@ impl CatchStrains {
pub const SECTION_LEN: f64 = 750.0; pub const SECTION_LEN: f64 = 750.0;
} }
pub fn strains(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> CatchStrains { pub fn strains(difficulty: &Difficulty, converted: &CatchBeatmap<'_>) -> CatchStrains {
let DifficultyValues { movement, .. } = DifficultyValues::calculate(difficulty, converted); let DifficultyValues { movement, .. } = DifficultyValues::calculate(difficulty, converted);
CatchStrains { CatchStrains {
+9 -6
View File
@@ -21,9 +21,9 @@
//! let map = rosu_pp::Beatmap::from_path("./resources/2785319.osu").unwrap(); //! let map = rosu_pp::Beatmap::from_path("./resources/2785319.osu").unwrap();
//! //!
//! // Calculate difficulty attributes //! // Calculate difficulty attributes
//! let diff_attrs = map.difficulty() //! let diff_attrs = rosu_pp::Difficulty::new()
//! .mods(8 + 16) // HDHR //! .mods(8 + 16) // HDHR
//! .calculate(); //! .calculate(&map);
//! //!
//! let stars = diff_attrs.stars(); //! let stars = diff_attrs.stars();
//! //!
@@ -62,12 +62,15 @@
//! score state. //! score state.
//! //!
//! ``` //! ```
//! use rosu_pp::{Beatmap, GradualPerformance, ModeDifficulty, any::ScoreState}; //! use rosu_pp::{Beatmap, GradualPerformance, Difficulty, any::ScoreState};
//! //!
//! let map = Beatmap::from_path("./resources/1028484.osu").unwrap(); //! let map = Beatmap::from_path("./resources/1028484.osu").unwrap();
//! let difficulty = ModeDifficulty::new().mods(16 + 64).clock_rate(1.2); // HRDT on 1.2x
//! //!
//! let mut gradual = GradualPerformance::new(&difficulty, &map); //! let mut gradual = Difficulty::new()
//! .mods(16 + 64) // HRDT
//! .clock_rate(1.2)
//! .gradual_performance(&map);
//!
//! let mut state = ScoreState::new(); // empty state, everything is on 0. //! let mut state = ScoreState::new(); // empty state, everything is on 0.
//! //!
//! // The first 10 hitresults are 300s //! // The first 10 hitresults are 300s
@@ -162,7 +165,7 @@
#[doc(inline)] #[doc(inline)]
pub use self::{ pub use self::{
any::{Difficulty, GradualDifficulty, GradualPerformance, ModeDifficulty, Performance}, any::{ConvertedDifficulty, Difficulty, GradualDifficulty, GradualPerformance, Performance},
model::beatmap::{Beatmap, Converted}, model::beatmap::{Beatmap, Converted},
}; };
+8 -8
View File
@@ -5,7 +5,7 @@ use crate::{
mania::{object::ObjectParams, ManiaBeatmap}, mania::{object::ObjectParams, ManiaBeatmap},
model::{beatmap::HitWindows, hit_object::HitObject}, model::{beatmap::HitWindows, hit_object::HitObject},
util::float_ext::FloatExt, util::float_ext::FloatExt,
ModeDifficulty, Difficulty,
}; };
use super::{ use super::{
@@ -25,14 +25,14 @@ use super::{
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::mania::ManiaGradualDifficulty; /// use rosu_pp::mania::ManiaGradualDifficulty;
/// ///
/// let converted = Beatmap::from_path("./resources/1638954.osu") /// let converted = Beatmap::from_path("./resources/1638954.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted(); /// .unchecked_into_converted();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut iter = ManiaGradualDifficulty::new(&difficulty, &converted); /// let mut iter = ManiaGradualDifficulty::new(&difficulty, &converted);
/// ///
/// // the difficulty of the map after the first hit object /// // the difficulty of the map after the first hit object
@@ -61,7 +61,7 @@ pub struct ManiaGradualDifficulty {
impl ManiaGradualDifficulty { impl ManiaGradualDifficulty {
/// Create a new difficulty attributes iterator for osu!mania maps. /// Create a new difficulty attributes iterator for osu!mania maps.
pub fn new(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &ManiaBeatmap<'_>) -> Self {
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let total_columns = converted.cs.round_even().max(1.0); let total_columns = converted.cs.round_even().max(1.0);
@@ -209,7 +209,7 @@ fn increment_combo_raw(is_circle: bool, start_time: f64, end_time: f64, curr_com
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{mania::Mania, Beatmap}; use crate::{any::difficulty::converted::ConvertedDifficulty, mania::Mania, Beatmap};
use super::*; use super::*;
@@ -219,7 +219,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted::<Mania>(); .unchecked_into_converted::<Mania>();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = ManiaGradualDifficulty::new(&difficulty, &converted); let mut gradual = ManiaGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none()); assert!(gradual.next().is_none());
@@ -231,7 +231,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted::<Mania>(); .unchecked_into_converted::<Mania>();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = ManiaGradualDifficulty::new(&difficulty, &converted); let mut gradual = ManiaGradualDifficulty::new(&difficulty, &converted);
let mut gradual_2nd = ManiaGradualDifficulty::new(&difficulty, &converted); let mut gradual_2nd = ManiaGradualDifficulty::new(&difficulty, &converted);
@@ -257,7 +257,7 @@ mod tests {
assert_eq!(next_gradual, next_gradual_3rd); assert_eq!(next_gradual, next_gradual_3rd);
} }
let expected = ModeDifficulty::new() let expected = ConvertedDifficulty::new()
.passed_objects(i as u32) .passed_objects(i as u32)
.calculate(&converted); .calculate(&converted);
+3 -3
View File
@@ -1,7 +1,7 @@
use std::cmp; use std::cmp;
use crate::{ use crate::{
any::difficulty::{mode::ModeDifficulty, skills::Skill}, any::difficulty::{skills::Skill, Difficulty},
mania::{ mania::{
difficulty::{object::ManiaDifficultyObject, skills::strain::Strain}, difficulty::{object::ManiaDifficultyObject, skills::strain::Strain},
object::{ManiaObject, ObjectParams}, object::{ManiaObject, ObjectParams},
@@ -18,7 +18,7 @@ mod skills;
const STAR_SCALING_FACTOR: f64 = 0.018; const STAR_SCALING_FACTOR: f64 = 0.018;
pub fn difficulty( pub fn difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
converted: &ManiaBeatmap<'_>, converted: &ManiaBeatmap<'_>,
) -> ManiaDifficultyAttributes { ) -> ManiaDifficultyAttributes {
let n_objects = cmp::min(difficulty.get_passed_objects(), converted.hit_objects.len()) as u32; let n_objects = cmp::min(difficulty.get_passed_objects(), converted.hit_objects.len()) as u32;
@@ -47,7 +47,7 @@ pub struct DifficultyValues {
} }
impl DifficultyValues { impl DifficultyValues {
pub fn calculate(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self { pub fn calculate(difficulty: &Difficulty, converted: &ManiaBeatmap<'_>) -> Self {
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
let total_columns = converted.cs.round_even().max(1.0); let total_columns = converted.cs.round_even().max(1.0);
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
+5 -5
View File
@@ -1,9 +1,9 @@
use crate::{ use crate::{
any::ModeDifficulty,
model::{ model::{
beatmap::Beatmap, beatmap::Beatmap,
mode::{ConvertStatus, IGameMode}, mode::{ConvertStatus, IGameMode},
}, },
Difficulty,
}; };
pub use self::{ pub use self::{
@@ -44,13 +44,13 @@ impl IGameMode for Mania {
} }
fn difficulty( fn difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
converted: &ManiaBeatmap<'_>, converted: &ManiaBeatmap<'_>,
) -> Self::DifficultyAttributes { ) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted) difficulty::difficulty(difficulty, converted)
} }
fn strains(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self::Strains { fn strains(difficulty: &Difficulty, converted: &ManiaBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted) strains::strains(difficulty, converted)
} }
@@ -59,14 +59,14 @@ impl IGameMode for Mania {
} }
fn gradual_difficulty( fn gradual_difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &ManiaBeatmap<'_>, map: &ManiaBeatmap<'_>,
) -> Self::GradualDifficulty { ) -> Self::GradualDifficulty {
ManiaGradualDifficulty::new(difficulty, map) ManiaGradualDifficulty::new(difficulty, map)
} }
fn gradual_performance( fn gradual_performance(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &ManiaBeatmap<'_>, map: &ManiaBeatmap<'_>,
) -> Self::GradualPerformance { ) -> Self::GradualPerformance {
ManiaGradualPerformance::new(difficulty, map) ManiaGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{ use crate::{
mania::{ManiaBeatmap, ManiaGradualDifficulty}, mania::{ManiaBeatmap, ManiaGradualDifficulty},
ModeDifficulty, Difficulty,
}; };
use super::{ManiaPerformanceAttributes, ManiaScoreState}; use super::{ManiaPerformanceAttributes, ManiaScoreState};
@@ -20,14 +20,14 @@ use super::{ManiaPerformanceAttributes, ManiaScoreState};
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::mania::{Mania, ManiaGradualPerformance, ManiaScoreState}; /// use rosu_pp::mania::{Mania, ManiaGradualPerformance, ManiaScoreState};
/// ///
/// let converted = Beatmap::from_path("./resources/1638954.osu") /// let converted = Beatmap::from_path("./resources/1638954.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted::<Mania>(); /// .unchecked_into_converted::<Mania>();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut gradual = ManiaGradualPerformance::new(&difficulty, &converted); /// let mut gradual = ManiaGradualPerformance::new(&difficulty, &converted);
/// let mut state = ManiaScoreState::new(); // empty state, everything is on 0. /// let mut state = ManiaScoreState::new(); // empty state, everything is on 0.
/// ///
@@ -75,7 +75,7 @@ pub struct ManiaGradualPerformance {
impl ManiaGradualPerformance { impl ManiaGradualPerformance {
/// Create a new gradual performance calculator for osu!mania maps. /// Create a new gradual performance calculator for osu!mania maps.
pub fn new(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &ManiaBeatmap<'_>) -> Self {
let difficulty = ManiaGradualDifficulty::new(difficulty, converted); let difficulty = ManiaGradualDifficulty::new(difficulty, converted);
Self { difficulty } Self { difficulty }
@@ -129,7 +129,7 @@ mod tests {
.unchecked_into_converted::<Mania>(); .unchecked_into_converted::<Mania>();
let mods = 88; // HDHRDT let mods = 88; // HDHRDT
let difficulty = ModeDifficulty::new().mods(88); let difficulty = Difficulty::new().mods(88);
let mut gradual = ManiaGradualPerformance::new(&difficulty, &converted); let mut gradual = ManiaGradualPerformance::new(&difficulty, &converted);
let mut gradual_2nd = ManiaGradualPerformance::new(&difficulty, &converted); let mut gradual_2nd = ManiaGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -1,8 +1,7 @@
use std::cmp; use std::cmp;
use crate::{ use crate::{
any::ModeDifficulty, any::{Difficulty, HitResultPriority, ModeAttributeProvider},
any::{HitResultPriority, ModeAttributeProvider},
osu::OsuPerformance, osu::OsuPerformance,
util::{map_or_attrs::MapOrAttrs, mods::Mods}, util::{map_or_attrs::MapOrAttrs, mods::Mods},
}; };
@@ -21,7 +20,7 @@ pub mod gradual;
#[must_use] #[must_use]
pub struct ManiaPerformance<'map> { pub struct ManiaPerformance<'map> {
map_or_attrs: MapOrAttrs<'map, Mania>, map_or_attrs: MapOrAttrs<'map, Mania>,
difficulty: ModeDifficulty, difficulty: Difficulty,
n320: Option<u32>, n320: Option<u32>,
n300: Option<u32>, n300: Option<u32>,
n200: Option<u32>, n200: Option<u32>,
@@ -37,7 +36,7 @@ impl<'map> ManiaPerformance<'map> {
pub const fn new(map: ManiaBeatmap<'map>) -> Self { pub const fn new(map: ManiaBeatmap<'map>) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Map(map), map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
n320: None, n320: None,
n300: None, n300: None,
n200: None, n200: None,
@@ -52,7 +51,7 @@ impl<'map> ManiaPerformance<'map> {
pub(crate) const fn from_mania_attributes(attrs: ManiaDifficultyAttributes) -> Self { pub(crate) const fn from_mania_attributes(attrs: ManiaDifficultyAttributes) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Attrs(attrs), map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
n320: None, n320: None,
n300: None, n300: None,
n200: None, n200: None,
@@ -192,7 +191,7 @@ impl<'map> ManiaPerformance<'map> {
pub fn generate_state(&mut self) -> ManiaScoreState { pub fn generate_state(&mut self) -> ManiaScoreState {
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => { MapOrAttrs::Map(ref map) => {
let attrs = self.generate_attributes(map); let attrs = self.difficulty.with_mode().calculate(map);
self.map_or_attrs.insert_attrs(attrs) self.map_or_attrs.insert_attrs(attrs)
} }
@@ -718,7 +717,7 @@ impl<'map> ManiaPerformance<'map> {
let state = self.generate_state(); let state = self.generate_state();
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => self.generate_attributes(map), MapOrAttrs::Map(ref map) => self.difficulty.with_mode().calculate(map),
MapOrAttrs::Attrs(attrs) => attrs, MapOrAttrs::Attrs(attrs) => attrs,
}; };
@@ -731,10 +730,6 @@ impl<'map> ManiaPerformance<'map> {
inner.calculate() inner.calculate()
} }
fn generate_attributes(&self, map: &ManiaBeatmap<'_>) -> ManiaDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`ManiaPerformance`] through a [`ModeAttributeProvider`]. /// Try to create [`ManiaPerformance`] through a [`ModeAttributeProvider`].
/// ///
/// If you already calculated the attributes for the current map-mod /// If you already calculated the attributes for the current map-mod
@@ -921,7 +916,7 @@ mod tests {
use proptest::prelude::*; use proptest::prelude::*;
use crate::Beatmap; use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*; use super::*;
@@ -936,7 +931,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted::<Mania>(); .unchecked_into_converted::<Mania>();
let attrs = ModeDifficulty::new().calculate(&converted); let attrs = ConvertedDifficulty::new().calculate(&converted);
assert_eq!(N_OBJECTS, converted.hit_objects.len() as u32); assert_eq!(N_OBJECTS, converted.hit_objects.len() as u32);
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::{any::ModeDifficulty, mania::difficulty::DifficultyValues}; use crate::{any::Difficulty, mania::difficulty::DifficultyValues};
use super::convert::ManiaBeatmap; use super::convert::ManiaBeatmap;
@@ -16,7 +16,7 @@ impl ManiaStrains {
pub const SECTION_LEN: f64 = 400.0; pub const SECTION_LEN: f64 = 400.0;
} }
pub fn strains(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> ManiaStrains { pub fn strains(difficulty: &Difficulty, converted: &ManiaBeatmap<'_>) -> ManiaStrains {
let values = DifficultyValues::calculate(difficulty, converted); let values = DifficultyValues::calculate(difficulty, converted);
ManiaStrains { ManiaStrains {
+7 -32
View File
@@ -1,5 +1,4 @@
use std::{ use std::{
any,
borrow::Cow, borrow::Cow,
fmt::{Debug, Formatter, Result as FmtResult}, fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData, marker::PhantomData,
@@ -8,7 +7,8 @@ use std::{
use crate::{ use crate::{
model::mode::{ConvertStatus, IGameMode}, model::mode::{ConvertStatus, IGameMode},
ModeDifficulty, util::generic_fmt::GenericFormatter,
Difficulty,
}; };
use super::Beatmap; use super::Beatmap;
@@ -74,13 +74,13 @@ impl<M: IGameMode> Converted<'_, M> {
} }
/// Create a gradual difficulty calculator for the map. /// Create a gradual difficulty calculator for the map.
pub fn gradual_difficulty(&self, difficulty: &ModeDifficulty) -> M::GradualDifficulty { pub fn gradual_difficulty(&self, difficulty: &Difficulty) -> M::GradualDifficulty {
difficulty.gradual_difficulty(self) M::gradual_difficulty(difficulty, self)
} }
/// Create a gradual performance calculator for the map. /// Create a gradual performance calculator for the map.
pub fn gradual_performance(&self, difficulty: &ModeDifficulty) -> M::GradualPerformance { pub fn gradual_performance(&self, difficulty: &Difficulty) -> M::GradualPerformance {
difficulty.gradual_performance(self) M::gradual_performance(difficulty, self)
} }
} }
@@ -189,34 +189,9 @@ impl<M> Clone for Converted<'_, M> {
impl<M> Debug for Converted<'_, M> { impl<M> Debug for Converted<'_, M> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
struct GenericFormatter<T>(PhantomData<T>);
impl<T> Default for GenericFormatter<T> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<T> Debug for GenericFormatter<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
fn fmt_stripped(full_type_name: &str, f: &mut Formatter<'_>) -> FmtResult {
// Strip fully qualified syntax
if let Some(position) = full_type_name.rfind("::") {
if let Some(type_name) = full_type_name.get(position + 2..) {
f.write_str(type_name)?;
}
}
Ok(())
}
fmt_stripped(any::type_name::<T>(), f)
}
}
f.debug_struct("Converted") f.debug_struct("Converted")
.field("map", &self.map) .field("map", &self.map)
.field("mode", &GenericFormatter::<M>::default()) .field("mode", &GenericFormatter::<M>::new())
.finish() .finish()
} }
} }
+4 -9
View File
@@ -7,7 +7,7 @@ use rosu_map::{
use crate::{ use crate::{
catch::Catch, mania::Mania, osu::Osu, taiko::Taiko, Difficulty, GradualDifficulty, catch::Catch, mania::Mania, osu::Osu, taiko::Taiko, Difficulty, GradualDifficulty,
GradualPerformance, ModeDifficulty, Performance, GradualPerformance, Performance,
}; };
pub use self::{ pub use self::{
@@ -85,23 +85,18 @@ impl Beatmap {
bpm::bpm(self.hit_objects.last(), &self.timing_points) bpm::bpm(self.hit_objects.last(), &self.timing_points)
} }
/// Create a difficulty calculator for this [`Beatmap`].
pub const fn difficulty(&self) -> Difficulty<'_> {
Difficulty::new(self)
}
/// Create a performance calculator for this [`Beatmap`]. /// Create a performance calculator for this [`Beatmap`].
pub const fn performance(&self) -> Performance<'_> { pub const fn performance(&self) -> Performance<'_> {
Performance::new(self) Performance::new(self)
} }
/// Create a gradual difficulty calculator for this [`Beatmap`]. /// Create a gradual difficulty calculator for this [`Beatmap`].
pub fn gradual_difficulty(&self, difficulty: &ModeDifficulty) -> GradualDifficulty { pub fn gradual_difficulty(&self, difficulty: &Difficulty) -> GradualDifficulty {
GradualDifficulty::new(difficulty, self) GradualDifficulty::new(difficulty, self)
} }
/// Create a gradual performance calculator for this [`Beatmap`]. /// Create a gradual performance calculator for this [`Beatmap`].
pub fn gradual_performance(&self, difficulty: &ModeDifficulty) -> GradualPerformance { pub fn gradual_performance(&self, difficulty: &Difficulty) -> GradualPerformance {
GradualPerformance::new(difficulty, self) GradualPerformance::new(difficulty, self)
} }
@@ -126,7 +121,7 @@ impl Beatmap {
} }
/// Convert a [`&mut Beatmap`] to the specified mode with an argument /// Convert a [`&mut Beatmap`] to the specified mode with an argument
/// instead of a generic parameter and return the [`ConvertStatus`]. /// instead of a generic parameter.
/// ///
/// [`&mut Beatmap`]: Beatmap /// [`&mut Beatmap`]: Beatmap
pub fn convert_inplace(&mut self, mode: GameMode) -> ConvertStatus { pub fn convert_inplace(&mut self, mode: GameMode) -> ConvertStatus {
+6 -8
View File
@@ -1,6 +1,6 @@
pub use rosu_map::section::general::GameMode; pub use rosu_map::section::general::GameMode;
use crate::any::ModeDifficulty; use crate::Difficulty;
use super::beatmap::{Beatmap, Converted}; use super::beatmap::{Beatmap, Converted};
@@ -40,27 +40,25 @@ pub trait IGameMode: Sized {
/// Perform a difficulty calculation for a [`Converted`] beatmap and /// Perform a difficulty calculation for a [`Converted`] beatmap and
/// process the final skill values. /// process the final skill values.
fn difficulty( fn difficulty(difficulty: &Difficulty, map: &Converted<'_, Self>)
difficulty: &ModeDifficulty, -> Self::DifficultyAttributes;
map: &Converted<'_, Self>,
) -> Self::DifficultyAttributes;
/// Perform a difficulty calculation for a [`Converted`] beatmap without /// Perform a difficulty calculation for a [`Converted`] beatmap without
/// processing the final skill values. /// processing the final skill values.
fn strains(difficulty: &ModeDifficulty, map: &Converted<'_, Self>) -> Self::Strains; fn strains(difficulty: &Difficulty, map: &Converted<'_, Self>) -> Self::Strains;
/// Create a performance calculator for a [`Converted`] beatmap. /// Create a performance calculator for a [`Converted`] beatmap.
fn performance(map: Converted<'_, Self>) -> Self::Performance<'_>; fn performance(map: Converted<'_, Self>) -> Self::Performance<'_>;
/// Create a gradual difficulty calculator for a [`Converted`] beatmap. /// Create a gradual difficulty calculator for a [`Converted`] beatmap.
fn gradual_difficulty( fn gradual_difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &Converted<'_, Self>, map: &Converted<'_, Self>,
) -> Self::GradualDifficulty; ) -> Self::GradualDifficulty;
/// Create a gradual performance calculator for a [`Converted`] beatmap. /// Create a gradual performance calculator for a [`Converted`] beatmap.
fn gradual_performance( fn gradual_performance(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &Converted<'_, Self>, map: &Converted<'_, Self>,
) -> Self::GradualPerformance; ) -> Self::GradualPerformance;
} }
+8 -8
View File
@@ -8,7 +8,7 @@ use crate::{
OsuBeatmap, OsuBeatmap,
}, },
util::mods::Mods, util::mods::Mods,
ModeDifficulty, Difficulty,
}; };
use self::osu_objects::OsuObjects; use self::osu_objects::OsuObjects;
@@ -31,14 +31,14 @@ use super::{
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::osu::{Osu, OsuGradualDifficulty}; /// use rosu_pp::osu::{Osu, OsuGradualDifficulty};
/// ///
/// let converted = Beatmap::from_path("./resources/2785319.osu") /// let converted = Beatmap::from_path("./resources/2785319.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted::<Osu>(); /// .unchecked_into_converted::<Osu>();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut iter = OsuGradualDifficulty::new(&difficulty, &converted); /// let mut iter = OsuGradualDifficulty::new(&difficulty, &converted);
/// ///
/// // the difficulty of the map after the first hit object /// // the difficulty of the map after the first hit object
@@ -73,7 +73,7 @@ struct NotClonable;
impl OsuGradualDifficulty { impl OsuGradualDifficulty {
/// Create a new difficulty attributes iterator for osu!standard maps. /// Create a new difficulty attributes iterator for osu!standard maps.
pub fn new(difficulty: &ModeDifficulty, converted: &OsuBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> Self {
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
@@ -262,7 +262,7 @@ mod osu_objects {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{osu::Osu, Beatmap}; use crate::{any::difficulty::converted::ConvertedDifficulty, osu::Osu, Beatmap};
use super::*; use super::*;
@@ -272,7 +272,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted::<Osu>(); .unchecked_into_converted::<Osu>();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = OsuGradualDifficulty::new(&difficulty, &converted); let mut gradual = OsuGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none()); assert!(gradual.next().is_none());
@@ -284,7 +284,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted::<Osu>(); .unchecked_into_converted::<Osu>();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = OsuGradualDifficulty::new(&difficulty, &converted); let mut gradual = OsuGradualDifficulty::new(&difficulty, &converted);
let mut gradual_2nd = OsuGradualDifficulty::new(&difficulty, &converted); let mut gradual_2nd = OsuGradualDifficulty::new(&difficulty, &converted);
@@ -310,7 +310,7 @@ mod tests {
assert_eq!(next_gradual, next_gradual_3rd); assert_eq!(next_gradual, next_gradual_3rd);
} }
let expected = ModeDifficulty::new() let expected = ConvertedDifficulty::new()
.passed_objects(i as u32) .passed_objects(i as u32)
.calculate(&converted); .calculate(&converted);
+5 -8
View File
@@ -1,7 +1,7 @@
use std::{cmp, pin::Pin}; use std::{cmp, pin::Pin};
use crate::{ use crate::{
any::difficulty::{mode::ModeDifficulty, skills::Skill}, any::difficulty::{skills::Skill, Difficulty},
model::beatmap::BeatmapAttributes, model::beatmap::BeatmapAttributes,
osu::{ osu::{
convert::convert_objects, convert::convert_objects,
@@ -26,10 +26,7 @@ const DIFFICULTY_MULTIPLIER: f64 = 0.0675;
const HD_FADE_IN_DURATION_MULTIPLIER: f64 = 0.4; const HD_FADE_IN_DURATION_MULTIPLIER: f64 = 0.4;
const HD_FADE_OUT_DURATION_MULTIPLIER: f64 = 0.3; const HD_FADE_OUT_DURATION_MULTIPLIER: f64 = 0.3;
pub fn difficulty( pub fn difficulty(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> OsuDifficultyAttributes {
difficulty: &ModeDifficulty,
converted: &OsuBeatmap<'_>,
) -> OsuDifficultyAttributes {
let DifficultyValues { let DifficultyValues {
skills: skills:
OsuSkills { OsuSkills {
@@ -70,7 +67,7 @@ pub struct OsuDifficultySetup {
} }
impl OsuDifficultySetup { impl OsuDifficultySetup {
pub fn new(difficulty: &ModeDifficulty, converted: &OsuBeatmap) -> Self { pub fn new(difficulty: &Difficulty, converted: &OsuBeatmap) -> Self {
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
@@ -106,7 +103,7 @@ pub struct DifficultyValues {
} }
impl DifficultyValues { impl DifficultyValues {
pub fn calculate(difficulty: &ModeDifficulty, converted: &OsuBeatmap<'_>) -> Self { pub fn calculate(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> Self {
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
@@ -218,7 +215,7 @@ impl DifficultyValues {
} }
pub fn create_difficulty_objects<'a>( pub fn create_difficulty_objects<'a>(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
scaling_factor: &ScalingFactor, scaling_factor: &ScalingFactor,
osu_objects: impl ExactSizeIterator<Item = Pin<&'a mut OsuObject>>, osu_objects: impl ExactSizeIterator<Item = Pin<&'a mut OsuObject>>,
) -> Vec<OsuDifficultyObject<'a>> { ) -> Vec<OsuDifficultyObject<'a>> {
+5 -5
View File
@@ -1,11 +1,11 @@
use rosu_map::util::Pos; use rosu_map::util::Pos;
use crate::{ use crate::{
any::ModeDifficulty,
model::{ model::{
beatmap::Beatmap, beatmap::Beatmap,
mode::{ConvertStatus, IGameMode}, mode::{ConvertStatus, IGameMode},
}, },
Difficulty,
}; };
pub use self::{ pub use self::{
@@ -48,13 +48,13 @@ impl IGameMode for Osu {
} }
fn difficulty( fn difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
converted: &OsuBeatmap<'_>, converted: &OsuBeatmap<'_>,
) -> Self::DifficultyAttributes { ) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted) difficulty::difficulty(difficulty, converted)
} }
fn strains(difficulty: &ModeDifficulty, converted: &OsuBeatmap<'_>) -> Self::Strains { fn strains(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted) strains::strains(difficulty, converted)
} }
@@ -63,14 +63,14 @@ impl IGameMode for Osu {
} }
fn gradual_difficulty( fn gradual_difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &OsuBeatmap<'_>, map: &OsuBeatmap<'_>,
) -> Self::GradualDifficulty { ) -> Self::GradualDifficulty {
OsuGradualDifficulty::new(difficulty, map) OsuGradualDifficulty::new(difficulty, map)
} }
fn gradual_performance( fn gradual_performance(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &OsuBeatmap<'_>, map: &OsuBeatmap<'_>,
) -> Self::GradualPerformance { ) -> Self::GradualPerformance {
OsuGradualPerformance::new(difficulty, map) OsuGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{ use crate::{
osu::{OsuBeatmap, OsuGradualDifficulty}, osu::{OsuBeatmap, OsuGradualDifficulty},
ModeDifficulty, Difficulty,
}; };
use super::{OsuPerformanceAttributes, OsuScoreState}; use super::{OsuPerformanceAttributes, OsuScoreState};
@@ -20,14 +20,14 @@ use super::{OsuPerformanceAttributes, OsuScoreState};
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::osu::{Osu, OsuGradualPerformance, OsuScoreState}; /// use rosu_pp::osu::{Osu, OsuGradualPerformance, OsuScoreState};
/// ///
/// let converted = Beatmap::from_path("./resources/2785319.osu") /// let converted = Beatmap::from_path("./resources/2785319.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted::<Osu>(); /// .unchecked_into_converted::<Osu>();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut gradual = OsuGradualPerformance::new(&difficulty, &converted); /// let mut gradual = OsuGradualPerformance::new(&difficulty, &converted);
/// let mut state = OsuScoreState::new(); // empty state, everything is on 0. /// let mut state = OsuScoreState::new(); // empty state, everything is on 0.
/// ///
@@ -85,7 +85,7 @@ pub struct OsuGradualPerformance {
impl OsuGradualPerformance { impl OsuGradualPerformance {
/// Create a new gradual performance calculator for osu!standard maps. /// Create a new gradual performance calculator for osu!standard maps.
pub fn new(difficulty: &ModeDifficulty, converted: &OsuBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> Self {
let difficulty = OsuGradualDifficulty::new(difficulty, converted); let difficulty = OsuGradualDifficulty::new(difficulty, converted);
Self { difficulty } Self { difficulty }
@@ -139,7 +139,7 @@ mod tests {
.unchecked_into_converted::<Osu>(); .unchecked_into_converted::<Osu>();
let mods = 88; // HDHRDT let mods = 88; // HDHRDT
let difficulty = ModeDifficulty::new().mods(88); let difficulty = Difficulty::new().mods(88);
let mut gradual = OsuGradualPerformance::new(&difficulty, &converted); let mut gradual = OsuGradualPerformance::new(&difficulty, &converted);
let mut gradual_2nd = OsuGradualPerformance::new(&difficulty, &converted); let mut gradual_2nd = OsuGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -3,8 +3,7 @@ use std::cmp;
use rosu_map::section::general::GameMode; use rosu_map::section::general::GameMode;
use crate::{ use crate::{
any::ModeDifficulty, any::{Difficulty, HitResultPriority, ModeAttributeProvider, Performance},
any::{HitResultPriority, ModeAttributeProvider, Performance},
catch::CatchPerformance, catch::CatchPerformance,
mania::ManiaPerformance, mania::ManiaPerformance,
taiko::TaikoPerformance, taiko::TaikoPerformance,
@@ -25,7 +24,7 @@ pub mod gradual;
#[must_use] #[must_use]
pub struct OsuPerformance<'map> { pub struct OsuPerformance<'map> {
pub(crate) map_or_attrs: MapOrAttrs<'map, Osu>, pub(crate) map_or_attrs: MapOrAttrs<'map, Osu>,
pub(crate) difficulty: ModeDifficulty, pub(crate) difficulty: Difficulty,
pub(crate) acc: Option<f64>, pub(crate) acc: Option<f64>,
pub(crate) combo: Option<u32>, pub(crate) combo: Option<u32>,
pub(crate) n300: Option<u32>, pub(crate) n300: Option<u32>,
@@ -40,7 +39,7 @@ impl<'map> OsuPerformance<'map> {
pub const fn new(map: OsuBeatmap<'map>) -> Self { pub const fn new(map: OsuBeatmap<'map>) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Map(map), map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
acc: None, acc: None,
combo: None, combo: None,
n300: None, n300: None,
@@ -54,7 +53,7 @@ impl<'map> OsuPerformance<'map> {
pub(crate) const fn from_osu_attributes(attrs: OsuDifficultyAttributes) -> Self { pub(crate) const fn from_osu_attributes(attrs: OsuDifficultyAttributes) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Attrs(attrs), map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
acc: None, acc: None,
combo: None, combo: None,
n300: None, n300: None,
@@ -233,7 +232,7 @@ impl<'map> OsuPerformance<'map> {
pub fn generate_state(&mut self) -> OsuScoreState { pub fn generate_state(&mut self) -> OsuScoreState {
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => { MapOrAttrs::Map(ref map) => {
let attrs = self.generate_attributes(map); let attrs = self.difficulty.with_mode().calculate(map);
self.map_or_attrs.insert_attrs(attrs) self.map_or_attrs.insert_attrs(attrs)
} }
@@ -417,7 +416,7 @@ impl<'map> OsuPerformance<'map> {
let state = self.generate_state(); let state = self.generate_state();
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => self.generate_attributes(map), MapOrAttrs::Map(ref map) => self.difficulty.with_mode().calculate(map),
MapOrAttrs::Attrs(attrs) => attrs, MapOrAttrs::Attrs(attrs) => attrs,
}; };
@@ -434,10 +433,6 @@ impl<'map> OsuPerformance<'map> {
inner.calculate() inner.calculate()
} }
fn generate_attributes(&self, map: &OsuBeatmap<'_>) -> OsuDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`OsuPerformance`] through a [`ModeAttributeProvider`]. /// Try to create [`OsuPerformance`] through a [`ModeAttributeProvider`].
/// ///
/// If you already calculated the attributes for the current map-mod /// If you already calculated the attributes for the current map-mod
@@ -828,7 +823,7 @@ mod test {
use proptest::prelude::*; use proptest::prelude::*;
use crate::Beatmap; use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*; use super::*;
@@ -843,7 +838,7 @@ mod test {
.unwrap() .unwrap()
.unchecked_into_converted::<Osu>(); .unchecked_into_converted::<Osu>();
let attrs = ModeDifficulty::new().calculate(&converted); let attrs = ConvertedDifficulty::new().calculate(&converted);
assert_eq!( assert_eq!(
(attrs.n_circles, attrs.n_sliders, attrs.n_spinners), (attrs.n_circles, attrs.n_sliders, attrs.n_spinners),
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::any::ModeDifficulty; use crate::Difficulty;
use super::{ use super::{
convert::OsuBeatmap, convert::OsuBeatmap,
@@ -25,7 +25,7 @@ impl OsuStrains {
pub const SECTION_LEN: f64 = 400.0; pub const SECTION_LEN: f64 = 400.0;
} }
pub fn strains(difficulty: &ModeDifficulty, converted: &OsuBeatmap<'_>) -> OsuStrains { pub fn strains(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> OsuStrains {
let DifficultyValues { let DifficultyValues {
skills: skills:
OsuSkills { OsuSkills {
+8 -9
View File
@@ -4,7 +4,7 @@ use crate::{
model::{beatmap::HitWindows, hit_object::HitObject}, model::{beatmap::HitWindows, hit_object::HitObject},
taiko::TaikoBeatmap, taiko::TaikoBeatmap,
util::sync::RefCount, util::sync::RefCount,
ModeDifficulty, Difficulty,
}; };
use super::{ use super::{
@@ -25,14 +25,14 @@ use super::{
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::taiko::{Taiko, TaikoGradualDifficulty}; /// use rosu_pp::taiko::{Taiko, TaikoGradualDifficulty};
/// ///
/// let converted = Beatmap::from_path("./resources/1028484.osu") /// let converted = Beatmap::from_path("./resources/1028484.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted::<Taiko>(); /// .unchecked_into_converted::<Taiko>();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut iter = TaikoGradualDifficulty::new(&difficulty, &converted); /// let mut iter = TaikoGradualDifficulty::new(&difficulty, &converted);
/// ///
/// // the difficulty of the map after the first hit object /// // the difficulty of the map after the first hit object
@@ -69,7 +69,7 @@ enum FirstTwoCombos {
impl TaikoGradualDifficulty { impl TaikoGradualDifficulty {
/// Create a new difficulty attributes iterator for osu!taiko maps. /// Create a new difficulty attributes iterator for osu!taiko maps.
pub fn new(difficulty: &ModeDifficulty, converted: &TaikoBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &TaikoBeatmap<'_>) -> Self {
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
@@ -260,8 +260,7 @@ impl ExactSizeIterator for TaikoGradualDifficulty {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use crate::Beatmap;
use super::*; use super::*;
@@ -269,7 +268,7 @@ mod tests {
fn empty() { fn empty() {
let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted(); let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted); let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none()); assert!(gradual.next().is_none());
@@ -281,7 +280,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted(); .unchecked_into_converted();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted); let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted);
let mut gradual_2nd = TaikoGradualDifficulty::new(&difficulty, &converted); let mut gradual_2nd = TaikoGradualDifficulty::new(&difficulty, &converted);
@@ -313,7 +312,7 @@ mod tests {
assert_eq!(next_gradual, next_gradual_3rd); assert_eq!(next_gradual, next_gradual_3rd);
} }
let expected = ModeDifficulty::new() let expected = ConvertedDifficulty::new()
.passed_objects(i as u32) .passed_objects(i as u32)
.calculate(&converted); .calculate(&converted);
+3 -3
View File
@@ -1,5 +1,4 @@
use crate::{ use crate::{
any::difficulty::mode::ModeDifficulty,
taiko::{ taiko::{
difficulty::{ difficulty::{
color::preprocessor::ColorDifficultyPreprocessor, color::preprocessor::ColorDifficultyPreprocessor,
@@ -8,6 +7,7 @@ use crate::{
}, },
object::TaikoObject, object::TaikoObject,
}, },
Difficulty,
}; };
use self::skills::peaks::Peaks; use self::skills::peaks::Peaks;
@@ -23,7 +23,7 @@ mod skills;
const DIFFICULTY_MULTIPLIER: f64 = 1.35; const DIFFICULTY_MULTIPLIER: f64 = 1.35;
pub fn difficulty( pub fn difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
converted: &TaikoBeatmap<'_>, converted: &TaikoBeatmap<'_>,
) -> TaikoDifficultyAttributes { ) -> TaikoDifficultyAttributes {
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
@@ -74,7 +74,7 @@ pub struct DifficultyValues {
} }
impl DifficultyValues { impl DifficultyValues {
pub fn calculate(difficulty: &ModeDifficulty, converted: &TaikoBeatmap<'_>) -> Self { pub fn calculate(difficulty: &Difficulty, converted: &TaikoBeatmap<'_>) -> Self {
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
+5 -5
View File
@@ -1,9 +1,9 @@
use crate::{ use crate::{
any::ModeDifficulty,
model::{ model::{
beatmap::Beatmap, beatmap::Beatmap,
mode::{ConvertStatus, IGameMode}, mode::{ConvertStatus, IGameMode},
}, },
Difficulty,
}; };
pub use self::{ pub use self::{
@@ -44,13 +44,13 @@ impl IGameMode for Taiko {
} }
fn difficulty( fn difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
converted: &TaikoBeatmap<'_>, converted: &TaikoBeatmap<'_>,
) -> Self::DifficultyAttributes { ) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted) difficulty::difficulty(difficulty, converted)
} }
fn strains(difficulty: &ModeDifficulty, converted: &TaikoBeatmap<'_>) -> Self::Strains { fn strains(difficulty: &Difficulty, converted: &TaikoBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted) strains::strains(difficulty, converted)
} }
@@ -59,14 +59,14 @@ impl IGameMode for Taiko {
} }
fn gradual_difficulty( fn gradual_difficulty(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &TaikoBeatmap<'_>, map: &TaikoBeatmap<'_>,
) -> Self::GradualDifficulty { ) -> Self::GradualDifficulty {
TaikoGradualDifficulty::new(difficulty, map) TaikoGradualDifficulty::new(difficulty, map)
} }
fn gradual_performance( fn gradual_performance(
difficulty: &ModeDifficulty, difficulty: &Difficulty,
map: &TaikoBeatmap<'_>, map: &TaikoBeatmap<'_>,
) -> Self::GradualPerformance { ) -> Self::GradualPerformance {
TaikoGradualPerformance::new(difficulty, map) TaikoGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{ use crate::{
taiko::{difficulty::gradual::TaikoGradualDifficulty, TaikoBeatmap, TaikoScoreState}, taiko::{difficulty::gradual::TaikoGradualDifficulty, TaikoBeatmap, TaikoScoreState},
ModeDifficulty, Difficulty,
}; };
use super::TaikoPerformanceAttributes; use super::TaikoPerformanceAttributes;
@@ -20,14 +20,14 @@ use super::TaikoPerformanceAttributes;
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use rosu_pp::{Beatmap, ModeDifficulty}; /// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::taiko::{Taiko, TaikoGradualPerformance, TaikoScoreState}; /// use rosu_pp::taiko::{Taiko, TaikoGradualPerformance, TaikoScoreState};
/// ///
/// let converted = Beatmap::from_path("./resources/1028484.osu") /// let converted = Beatmap::from_path("./resources/1028484.osu")
/// .unwrap() /// .unwrap()
/// .unchecked_into_converted::<Taiko>(); /// .unchecked_into_converted::<Taiko>();
/// ///
/// let difficulty = ModeDifficulty::new().mods(64); // DT /// let difficulty = Difficulty::new().mods(64); // DT
/// let mut gradual = TaikoGradualPerformance::new(&difficulty, &converted); /// let mut gradual = TaikoGradualPerformance::new(&difficulty, &converted);
/// let mut state = TaikoScoreState::new(); // empty state, everything is on 0. /// let mut state = TaikoScoreState::new(); // empty state, everything is on 0.
/// ///
@@ -84,7 +84,7 @@ pub struct TaikoGradualPerformance {
impl TaikoGradualPerformance { impl TaikoGradualPerformance {
/// Create a new gradual performance calculator for osu!taiko maps. /// Create a new gradual performance calculator for osu!taiko maps.
pub fn new(difficulty: &ModeDifficulty, converted: &TaikoBeatmap<'_>) -> Self { pub fn new(difficulty: &Difficulty, converted: &TaikoBeatmap<'_>) -> Self {
let difficulty = TaikoGradualDifficulty::new(difficulty, converted); let difficulty = TaikoGradualDifficulty::new(difficulty, converted);
Self { difficulty } Self { difficulty }
@@ -135,7 +135,7 @@ mod tests {
.unchecked_into_converted(); .unchecked_into_converted();
let mods = 88; // HDHRDT let mods = 88; // HDHRDT
let difficulty = ModeDifficulty::new().mods(88); let difficulty = Difficulty::new().mods(88);
let mut gradual = TaikoGradualPerformance::new(&difficulty, &converted); let mut gradual = TaikoGradualPerformance::new(&difficulty, &converted);
let mut gradual_2nd = TaikoGradualPerformance::new(&difficulty, &converted); let mut gradual_2nd = TaikoGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -1,8 +1,7 @@
use std::cmp; use std::cmp;
use crate::{ use crate::{
any::ModeDifficulty, any::{Difficulty, HitResultPriority, ModeAttributeProvider},
any::{HitResultPriority, ModeAttributeProvider},
osu::OsuPerformance, osu::OsuPerformance,
util::{map_or_attrs::MapOrAttrs, mods::Mods}, util::{map_or_attrs::MapOrAttrs, mods::Mods},
}; };
@@ -21,7 +20,7 @@ pub mod gradual;
#[must_use] #[must_use]
pub struct TaikoPerformance<'map> { pub struct TaikoPerformance<'map> {
pub(crate) map_or_attrs: MapOrAttrs<'map, Taiko>, pub(crate) map_or_attrs: MapOrAttrs<'map, Taiko>,
difficulty: ModeDifficulty, difficulty: Difficulty,
combo: Option<u32>, combo: Option<u32>,
acc: Option<f64>, acc: Option<f64>,
hitresult_priority: HitResultPriority, hitresult_priority: HitResultPriority,
@@ -35,7 +34,7 @@ impl<'map> TaikoPerformance<'map> {
pub const fn new(map: TaikoBeatmap<'map>) -> Self { pub const fn new(map: TaikoBeatmap<'map>) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Map(map), map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
combo: None, combo: None,
acc: None, acc: None,
misses: None, misses: None,
@@ -48,7 +47,7 @@ impl<'map> TaikoPerformance<'map> {
pub(crate) const fn from_taiko_attributes(attrs: TaikoDifficultyAttributes) -> Self { pub(crate) const fn from_taiko_attributes(attrs: TaikoDifficultyAttributes) -> Self {
Self { Self {
map_or_attrs: MapOrAttrs::Attrs(attrs), map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(), difficulty: Difficulty::new(),
combo: None, combo: None,
acc: None, acc: None,
misses: None, misses: None,
@@ -167,7 +166,7 @@ impl<'map> TaikoPerformance<'map> {
pub fn generate_state(&mut self) -> TaikoScoreState { pub fn generate_state(&mut self) -> TaikoScoreState {
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => { MapOrAttrs::Map(ref map) => {
let attrs = self.generate_attributes(map); let attrs = self.difficulty.with_mode().calculate(map);
self.map_or_attrs.insert_attrs(attrs) self.map_or_attrs.insert_attrs(attrs)
} }
@@ -255,7 +254,7 @@ impl<'map> TaikoPerformance<'map> {
let state = self.generate_state(); let state = self.generate_state();
let attrs = match self.map_or_attrs { let attrs = match self.map_or_attrs {
MapOrAttrs::Map(ref map) => self.generate_attributes(map), MapOrAttrs::Map(ref map) => self.difficulty.with_mode().calculate(map),
MapOrAttrs::Attrs(attrs) => attrs, MapOrAttrs::Attrs(attrs) => attrs,
}; };
@@ -268,10 +267,6 @@ impl<'map> TaikoPerformance<'map> {
inner.calculate() inner.calculate()
} }
fn generate_attributes(&self, map: &TaikoBeatmap<'_>) -> TaikoDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`TaikoPerformance`] through a [`ModeAttributeProvider`]. /// Try to create [`TaikoPerformance`] through a [`ModeAttributeProvider`].
/// ///
/// If you already calculated the attributes for the current map-mod /// If you already calculated the attributes for the current map-mod
@@ -506,7 +501,7 @@ mod test {
use proptest::prelude::*; use proptest::prelude::*;
use crate::Beatmap; use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*; use super::*;
@@ -521,7 +516,7 @@ mod test {
.unwrap() .unwrap()
.unchecked_into_converted::<Taiko>(); .unchecked_into_converted::<Taiko>();
let attrs = ModeDifficulty::new().calculate(&converted); let attrs = ConvertedDifficulty::new().calculate(&converted);
assert_eq!(MAX_COMBO, attrs.max_combo); assert_eq!(MAX_COMBO, attrs.max_combo);
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::{any::ModeDifficulty, taiko::difficulty::DifficultyValues}; use crate::{taiko::difficulty::DifficultyValues, Difficulty};
use super::convert::TaikoBeatmap; use super::convert::TaikoBeatmap;
@@ -20,7 +20,7 @@ impl TaikoStrains {
pub const SECTION_LEN: f64 = 400.0; pub const SECTION_LEN: f64 = 400.0;
} }
pub fn strains(difficulty: &ModeDifficulty, converted: &TaikoBeatmap<'_>) -> TaikoStrains { pub fn strains(difficulty: &Difficulty, converted: &TaikoBeatmap<'_>) -> TaikoStrains {
let values = DifficultyValues::calculate(difficulty, converted); let values = DifficultyValues::calculate(difficulty, converted);
TaikoStrains { TaikoStrains {
+30
View File
@@ -0,0 +1,30 @@
use std::{
any,
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
};
pub struct GenericFormatter<T>(PhantomData<T>);
impl<T> GenericFormatter<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T> Debug for GenericFormatter<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
fn fmt_stripped(full_type_name: &str, f: &mut Formatter<'_>) -> FmtResult {
// Strip fully qualified syntax
if let Some(position) = full_type_name.rfind("::") {
if let Some(type_name) = full_type_name.get(position + 2..) {
f.write_str(type_name)?;
}
}
Ok(())
}
fmt_stripped(any::type_name::<T>(), f)
}
}
+1
View File
@@ -1,4 +1,5 @@
pub mod float_ext; pub mod float_ext;
pub mod generic_fmt;
pub mod limited_queue; pub mod limited_queue;
pub mod map_or_attrs; pub mod map_or_attrs;
pub mod mods; pub mod mods;
+4 -4
View File
@@ -133,10 +133,10 @@ impl<T: fmt::Debug> fmt::Debug for Weak<T> {
} }
/// ```compile_fail /// ```compile_fail
/// use rosu_pp::{taiko::TaikoGradualDifficulty, Beatmap, ModeDifficulty}; /// use rosu_pp::{taiko::TaikoGradualDifficulty, Beatmap, Difficulty};
/// ///
/// let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted(); /// let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted();
/// let difficulty = ModeDifficulty::new(); /// let difficulty = Difficulty::new();
/// let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted); /// let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted);
/// ///
/// // Rc<RefCell<_>> cannot be shared across threads so compilation should fail /// // Rc<RefCell<_>> cannot be shared across threads so compilation should fail
@@ -149,10 +149,10 @@ const fn _share_gradual_taiko() {}
mod tests { mod tests {
#[test] #[test]
fn share_gradual_taiko() { fn share_gradual_taiko() {
use crate::{taiko::TaikoGradualDifficulty, Beatmap, ModeDifficulty}; use crate::{taiko::TaikoGradualDifficulty, Beatmap, Difficulty};
let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted(); let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted();
let difficulty = ModeDifficulty::new(); let difficulty = Difficulty::new();
let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted); let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted);
// Arc<RwLock<_>> *can* be shared across threads so this should compile // Arc<RwLock<_>> *can* be shared across threads so this should compile
+2 -2
View File
@@ -5,7 +5,7 @@ use rosu_pp::{
mania::{Mania, ManiaDifficultyAttributes}, mania::{Mania, ManiaDifficultyAttributes},
osu::{Osu, OsuDifficultyAttributes}, osu::{Osu, OsuDifficultyAttributes},
taiko::{Taiko, TaikoDifficultyAttributes}, taiko::{Taiko, TaikoDifficultyAttributes},
Beatmap, ModeDifficulty, Beatmap, ConvertedDifficulty,
}; };
use self::common::*; use self::common::*;
@@ -25,7 +25,7 @@ macro_rules! test_cases {
$( $(
let mods = 0 $( + $mods )*; let mods = 0 $( + $mods )*;
let expected = test_cases!(@$mode { $( $key: $value, )* }); let expected = test_cases!(@$mode { $( $key: $value, )* });
let actual = ModeDifficulty::new().mods(mods).calculate(&map); let actual = ConvertedDifficulty::new().mods(mods).calculate(&map);
run(&actual, &expected, mods); run(&actual, &expected, mods);
)* )*
}; };