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();
// Calculate difficulty attributes
let diff_attrs = map.difficulty()
let diff_attrs = rosu_pp::Difficulty::new()
.mods(8 + 16) // HDHR
.calculate();
.calculate(&map);
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
separately and calculate the attributes only up to that point.
For difficulty attributes, there is [`GradualDifficulty`] which implements [`Iterator`]
and for performance attributes there is [`GradualPerformance`] which requires the current
For difficulty attributes, there is `GradualDifficulty` which implements `Iterator`
and for performance attributes there is `GradualPerformance` which requires the current
score state.
```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 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.
// 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::{
any::DifficultyAttributes,
catch::{CatchBeatmap, CatchGradualDifficulty},
mania::{ManiaBeatmap, ManiaGradualDifficulty},
osu::{OsuBeatmap, OsuGradualDifficulty},
taiko::{TaikoBeatmap, TaikoGradualDifficulty},
Beatmap, ModeDifficulty,
catch::{Catch, CatchBeatmap, CatchGradualDifficulty},
mania::{Mania, ManiaBeatmap, ManiaGradualDifficulty},
model::mode::IGameMode,
osu::{Osu, OsuBeatmap, OsuGradualDifficulty},
taiko::{Taiko, TaikoBeatmap, TaikoGradualDifficulty},
Beatmap, Converted, Difficulty,
};
/// Gradually calculate the difficulty attributes on maps of any mode.
@@ -22,10 +23,10 @@ use crate::{
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, GradualDifficulty, ModeDifficulty};
/// use rosu_pp::{Beatmap, GradualDifficulty, Difficulty};
///
/// 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);
///
/// // the difficulty of the map after the first object
@@ -53,22 +54,28 @@ pub enum GradualDifficulty {
macro_rules! from_converted {
( $fn:ident, $mode:ident, $converted:ident ) => {
#[doc = concat!("Create a [`GradualDifficulty`] for a [`", stringify!($converted), "`]")]
pub fn $fn(difficulty: &ModeDifficulty, converted: &$converted<'_>) -> Self {
Self::$mode(difficulty.gradual_difficulty(converted))
pub fn $fn(difficulty: &Difficulty, converted: &$converted<'_>) -> Self {
Self::$mode($mode::gradual_difficulty(difficulty, converted))
}
};
}
impl GradualDifficulty {
/// 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);
match map.mode {
GameMode::Osu => Self::Osu(difficulty.gradual_difficulty(&OsuBeatmap::new(map))),
GameMode::Taiko => Self::Taiko(difficulty.gradual_difficulty(&TaikoBeatmap::new(map))),
GameMode::Catch => Self::Catch(difficulty.gradual_difficulty(&CatchBeatmap::new(map))),
GameMode::Mania => Self::Mania(difficulty.gradual_difficulty(&ManiaBeatmap::new(map))),
GameMode::Osu => Self::Osu(Osu::gradual_difficulty(difficulty, &Converted::new(map))),
GameMode::Taiko => {
Self::Taiko(Taiko::gradual_difficulty(difficulty, &Converted::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 crate::{
catch::{Catch, CatchBeatmap},
mania::{Mania, ManiaBeatmap},
catch::Catch,
mania::Mania,
model::beatmap::{Beatmap, Converted},
osu::{Osu, OsuBeatmap},
taiko::{Taiko, TaikoBeatmap},
osu::Osu,
taiko::Taiko,
GradualDifficulty, GradualPerformance,
};
use self::mode::ModeDifficulty;
use self::converted::ConvertedDifficulty;
use super::{attributes::DifficultyAttributes, Strains};
pub mod converted;
pub mod gradual;
pub mod mode;
pub mod object;
pub mod skills;
use crate::{model::mode::IGameMode, util::mods::Mods};
/// Difficulty calculator on maps of any mode.
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq)]
#[must_use]
pub struct Difficulty<'map> {
map: Cow<'map, Beatmap>,
inner: ModeDifficulty,
pub struct Difficulty {
mods: u32,
passed_objects: Option<u32>,
clock_rate: Option<f64>,
}
impl<'map> Difficulty<'map> {
/// Create a new difficulty calculator for the given beatmap.
pub const fn new(map: &'map Beatmap) -> Self {
Self::new_with_cow(Cow::Borrowed(map))
}
const fn new_with_cow(map: Cow<'map, Beatmap>) -> Self {
impl Difficulty {
/// Create a new difficulty calculator.
pub const fn new() -> Self {
Self {
map,
inner: ModeDifficulty::new(),
mods: 0,
passed_objects: None,
clock_rate: None,
}
}
}
macro_rules! impl_from_mode {
( $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.
/// Use this [`&Difficulty`] as a calculator for a specific [`IGameMode`].
///
/// If the conversion is incompatible, `None` is returned.
///
/// If the given mode should be ignored in case it is incompatible, use
/// [`mode_or_ignore`] instead.
///
/// [`mode_or_ignore`]: Self::mode_or_ignore
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(),
/// [`&Difficulty`]: Difficulty
pub const fn with_mode<M: IGameMode>(&self) -> ConvertedDifficulty<M> {
let this = Self {
mods: self.mods,
passed_objects: self.passed_objects,
clock_rate: self.clock_rate,
};
if matches!(map, Cow::Owned(_)) {
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
ConvertedDifficulty::from_difficulty(this)
}
/// Specify mods through their bit values.
///
/// See [https://github.com/ppy/osu-api/wiki#mods](https://github.com/ppy/osu-api/wiki#mods)
pub fn mods(self, mods: u32) -> Self {
Self {
inner: self.inner.mods(mods),
..self
}
pub const fn mods(self, mods: u32) -> Self {
Self { mods, ..self }
}
/// 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 {
inner: self.inner.passed_objects(passed_objects),
passed_objects: Some(passed_objects),
..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
/// 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),
clock_rate: Some(clock_rate.clamp(0.01, 100.0)),
..self
}
}
@@ -148,19 +83,19 @@ impl Difficulty<'_> {
/// Perform the difficulty calculation.
///
/// The returned attributes depend on the map's mode.
pub fn calculate(&self) -> DifficultyAttributes {
let map = Cow::Borrowed(self.map.as_ref());
pub fn calculate(&self, map: &Beatmap) -> DifficultyAttributes {
let map = Cow::Borrowed(map);
match self.map.mode {
GameMode::Osu => DifficultyAttributes::Osu(self.inner.calculate(&OsuBeatmap::new(map))),
match map.mode {
GameMode::Osu => DifficultyAttributes::Osu(Osu::difficulty(self, &Converted::new(map))),
GameMode::Taiko => {
DifficultyAttributes::Taiko(self.inner.calculate(&TaikoBeatmap::new(map)))
DifficultyAttributes::Taiko(Taiko::difficulty(self, &Converted::new(map)))
}
GameMode::Catch => {
DifficultyAttributes::Catch(self.inner.calculate(&CatchBeatmap::new(map)))
DifficultyAttributes::Catch(Catch::difficulty(self, &Converted::new(map)))
}
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.
///
/// Suitable to plot the difficulty of a map over time.
pub fn strains(&self) -> Strains {
let map = Cow::Borrowed(self.map.as_ref());
pub fn strains(&self, map: &Beatmap) -> Strains {
let map = Cow::Borrowed(map);
match self.map.mode {
GameMode::Osu => Strains::Osu(self.inner.strains(&OsuBeatmap::new(map))),
GameMode::Taiko => Strains::Taiko(self.inner.strains(&TaikoBeatmap::new(map))),
GameMode::Catch => Strains::Catch(self.inner.strains(&CatchBeatmap::new(map))),
GameMode::Mania => Strains::Mania(self.inner.strains(&ManiaBeatmap::new(map))),
match map.mode {
GameMode::Osu => Strains::Osu(Osu::strains(self, &Converted::new(map))),
GameMode::Taiko => Strains::Taiko(Taiko::strains(self, &Converted::new(map))),
GameMode::Catch => Strains::Catch(Catch::strains(self, &Converted::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::{
AttributeProvider, DifficultyAttributes, ModeAttributeProvider, PerformanceAttributes,
},
difficulty::{gradual::GradualDifficulty, mode::ModeDifficulty, Difficulty},
difficulty::{converted::ConvertedDifficulty, gradual::GradualDifficulty, Difficulty},
performance::{gradual::GradualPerformance, HitResultPriority, Performance},
score_state::ScoreState,
strains::Strains,
+21 -14
View File
@@ -4,11 +4,12 @@ use rosu_map::section::general::GameMode;
use crate::{
any::{PerformanceAttributes, ScoreState},
catch::{CatchBeatmap, CatchGradualPerformance},
mania::{ManiaBeatmap, ManiaGradualPerformance},
osu::{OsuBeatmap, OsuGradualPerformance},
taiko::{TaikoBeatmap, TaikoGradualPerformance},
Beatmap, ModeDifficulty,
catch::{Catch, CatchBeatmap, CatchGradualPerformance},
mania::{Mania, ManiaBeatmap, ManiaGradualPerformance},
model::mode::IGameMode,
osu::{Osu, OsuBeatmap, OsuGradualPerformance},
taiko::{Taiko, TaikoBeatmap, TaikoGradualPerformance},
Beatmap, Converted, Difficulty,
};
/// Gradually calculate the performance attributes on maps of any mode.
@@ -31,10 +32,10 @@ use crate::{
/// # 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 difficulty = ModeDifficulty::new().mods(64); // DT
/// let difficulty = Difficulty::new().mods(64); // DT
/// let mut gradual = GradualPerformance::new(&difficulty, &map);
/// let mut state = ScoreState::new(); // empty state, everything is on 0.
///
@@ -102,22 +103,28 @@ pub enum GradualPerformance {
macro_rules! from_converted {
( $fn:ident, $mode:ident, $converted:ident ) => {
#[doc = concat!("Create a [`GradualPerformance`] for a [`", stringify!($converted), "`]")]
pub fn $fn(difficulty: &ModeDifficulty, converted: &$converted<'_>) -> Self {
Self::$mode(difficulty.gradual_performance(converted))
pub fn $fn(difficulty: &Difficulty, converted: &$converted<'_>) -> Self {
Self::$mode($mode::gradual_performance(difficulty, converted))
}
};
}
impl GradualPerformance {
/// 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);
match map.mode {
GameMode::Osu => Self::Osu(difficulty.gradual_performance(&OsuBeatmap::new(map))),
GameMode::Taiko => Self::Taiko(difficulty.gradual_performance(&TaikoBeatmap::new(map))),
GameMode::Catch => Self::Catch(difficulty.gradual_performance(&CatchBeatmap::new(map))),
GameMode::Mania => Self::Mania(difficulty.gradual_performance(&ManiaBeatmap::new(map))),
GameMode::Osu => Self::Osu(Osu::gradual_performance(difficulty, &Converted::new(map))),
GameMode::Taiko => {
Self::Taiko(Taiko::gradual_performance(difficulty, &Converted::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,
},
util::mods::Mods,
ModeDifficulty,
Difficulty,
};
use super::{
@@ -32,14 +32,14 @@ use super::{
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::catch::{Catch, CatchGradualDifficulty};
///
/// let converted = Beatmap::from_path("./resources/2118524.osu")
/// .unwrap()
/// .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);
///
/// // the difficulty of the map after the first hit object
@@ -66,7 +66,7 @@ pub struct 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 clock_rate = difficulty.get_clock_rate();
@@ -163,7 +163,7 @@ impl ExactSizeIterator for CatchGradualDifficulty {
#[cfg(test)]
mod tests {
use crate::Beatmap;
use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*;
@@ -171,7 +171,7 @@ mod tests {
fn empty() {
let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = CatchGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none());
@@ -183,7 +183,7 @@ mod tests {
.unwrap()
.unchecked_into_converted();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = 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);
}
let expected = ModeDifficulty::new()
let expected = ConvertedDifficulty::new()
.passed_objects(i as u32)
.calculate(&converted);
+4 -4
View File
@@ -1,5 +1,5 @@
use crate::{
any::difficulty::{mode::ModeDifficulty, skills::Skill},
any::difficulty::{skills::Skill, Difficulty},
catch::{
catcher::Catcher, convert::convert_objects, difficulty::object::CatchDifficultyObject,
},
@@ -22,7 +22,7 @@ mod skills;
const STAR_SCALING_FACTOR: f64 = 0.153;
pub fn difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
converted: &CatchBeatmap<'_>,
) -> CatchDifficultyAttributes {
let DifficultyValues {
@@ -41,7 +41,7 @@ pub struct 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 clock_rate = difficulty.get_clock_rate();
@@ -67,7 +67,7 @@ pub struct 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 mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate();
+5 -5
View File
@@ -1,9 +1,9 @@
use crate::{
any::ModeDifficulty,
model::{
beatmap::Beatmap,
mode::{ConvertStatus, IGameMode},
},
Difficulty,
};
pub use self::{
@@ -47,13 +47,13 @@ impl IGameMode for Catch {
}
fn difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
converted: &CatchBeatmap<'_>,
) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted)
}
fn strains(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> Self::Strains {
fn strains(difficulty: &Difficulty, converted: &CatchBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted)
}
@@ -62,14 +62,14 @@ impl IGameMode for Catch {
}
fn gradual_difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &CatchBeatmap<'_>,
) -> Self::GradualDifficulty {
CatchGradualDifficulty::new(difficulty, map)
}
fn gradual_performance(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &CatchBeatmap<'_>,
) -> Self::GradualPerformance {
CatchGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{
catch::{CatchBeatmap, CatchGradualDifficulty, CatchPerformanceAttributes, CatchScoreState},
ModeDifficulty,
Difficulty,
};
/// Gradually calculate the performance attributes of an osu!catch map.
@@ -21,14 +21,14 @@ use crate::{
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::catch::{Catch, CatchGradualPerformance, CatchScoreState};
///
/// let converted = Beatmap::from_path("./resources/2118524.osu")
/// .unwrap()
/// .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 state = CatchScoreState::new(); // empty state, everything is on 0.
///
@@ -90,7 +90,7 @@ pub struct CatchGradualPerformance {
impl CatchGradualPerformance {
/// 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);
Self { difficulty }
@@ -144,7 +144,7 @@ mod tests {
.unchecked_into_converted();
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_2nd = CatchGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -1,8 +1,7 @@
use std::cmp::{self, Ordering};
use crate::{
any::ModeAttributeProvider,
any::ModeDifficulty,
any::{Difficulty, ModeAttributeProvider},
osu::OsuPerformance,
util::{map_or_attrs::MapOrAttrs, mods::Mods},
};
@@ -21,7 +20,7 @@ pub mod gradual;
#[must_use]
pub struct CatchPerformance<'map> {
map_or_attrs: MapOrAttrs<'map, Catch>,
difficulty: ModeDifficulty,
difficulty: Difficulty,
acc: Option<f64>,
combo: Option<u32>,
fruits: Option<u32>,
@@ -36,7 +35,7 @@ impl<'map> CatchPerformance<'map> {
pub const fn new(map: CatchBeatmap<'map>) -> Self {
Self {
map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
acc: None,
combo: None,
fruits: None,
@@ -50,7 +49,7 @@ impl<'map> CatchPerformance<'map> {
pub(crate) const fn from_catch_attributes(attrs: CatchDifficultyAttributes) -> Self {
Self {
map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
acc: None,
combo: None,
fruits: None,
@@ -180,7 +179,7 @@ impl<'map> CatchPerformance<'map> {
pub fn generate_state(&mut self) -> CatchScoreState {
let attrs = match self.map_or_attrs {
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)
}
@@ -327,7 +326,7 @@ impl<'map> CatchPerformance<'map> {
let state = self.generate_state();
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,
};
@@ -340,10 +339,6 @@ impl<'map> CatchPerformance<'map> {
inner.calculate()
}
fn generate_attributes(&self, map: &CatchBeatmap<'_>) -> CatchDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`CatchPerformance`] through a [`ModeAttributeProvider`].
///
/// If you already calculated the attributes for the current map-mod
@@ -547,7 +542,7 @@ mod test {
use proptest::prelude::*;
use crate::Beatmap;
use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*;
@@ -564,7 +559,7 @@ mod test {
.unwrap()
.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_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;
@@ -16,7 +16,7 @@ impl CatchStrains {
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);
CatchStrains {
+9 -6
View File
@@ -21,9 +21,9 @@
//! let map = rosu_pp::Beatmap::from_path("./resources/2785319.osu").unwrap();
//!
//! // Calculate difficulty attributes
//! let diff_attrs = map.difficulty()
//! let diff_attrs = rosu_pp::Difficulty::new()
//! .mods(8 + 16) // HDHR
//! .calculate();
//! .calculate(&map);
//!
//! let stars = diff_attrs.stars();
//!
@@ -62,12 +62,15 @@
//! 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 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.
//!
//! // The first 10 hitresults are 300s
@@ -162,7 +165,7 @@
#[doc(inline)]
pub use self::{
any::{Difficulty, GradualDifficulty, GradualPerformance, ModeDifficulty, Performance},
any::{ConvertedDifficulty, Difficulty, GradualDifficulty, GradualPerformance, Performance},
model::beatmap::{Beatmap, Converted},
};
+8 -8
View File
@@ -5,7 +5,7 @@ use crate::{
mania::{object::ObjectParams, ManiaBeatmap},
model::{beatmap::HitWindows, hit_object::HitObject},
util::float_ext::FloatExt,
ModeDifficulty,
Difficulty,
};
use super::{
@@ -25,14 +25,14 @@ use super::{
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::mania::ManiaGradualDifficulty;
///
/// let converted = Beatmap::from_path("./resources/1638954.osu")
/// .unwrap()
/// .unchecked_into_converted();
///
/// let difficulty = ModeDifficulty::new().mods(64); // DT
/// let difficulty = Difficulty::new().mods(64); // DT
/// let mut iter = ManiaGradualDifficulty::new(&difficulty, &converted);
///
/// // the difficulty of the map after the first hit object
@@ -61,7 +61,7 @@ pub struct ManiaGradualDifficulty {
impl ManiaGradualDifficulty {
/// 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 mods = difficulty.get_mods();
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)]
mod tests {
use crate::{mania::Mania, Beatmap};
use crate::{any::difficulty::converted::ConvertedDifficulty, mania::Mania, Beatmap};
use super::*;
@@ -219,7 +219,7 @@ mod tests {
.unwrap()
.unchecked_into_converted::<Mania>();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = ManiaGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none());
@@ -231,7 +231,7 @@ mod tests {
.unwrap()
.unchecked_into_converted::<Mania>();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = 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);
}
let expected = ModeDifficulty::new()
let expected = ConvertedDifficulty::new()
.passed_objects(i as u32)
.calculate(&converted);
+3 -3
View File
@@ -1,7 +1,7 @@
use std::cmp;
use crate::{
any::difficulty::{mode::ModeDifficulty, skills::Skill},
any::difficulty::{skills::Skill, Difficulty},
mania::{
difficulty::{object::ManiaDifficultyObject, skills::strain::Strain},
object::{ManiaObject, ObjectParams},
@@ -18,7 +18,7 @@ mod skills;
const STAR_SCALING_FACTOR: f64 = 0.018;
pub fn difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
converted: &ManiaBeatmap<'_>,
) -> ManiaDifficultyAttributes {
let n_objects = cmp::min(difficulty.get_passed_objects(), converted.hit_objects.len()) as u32;
@@ -47,7 +47,7 @@ pub struct 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 total_columns = converted.cs.round_even().max(1.0);
let clock_rate = difficulty.get_clock_rate();
+5 -5
View File
@@ -1,9 +1,9 @@
use crate::{
any::ModeDifficulty,
model::{
beatmap::Beatmap,
mode::{ConvertStatus, IGameMode},
},
Difficulty,
};
pub use self::{
@@ -44,13 +44,13 @@ impl IGameMode for Mania {
}
fn difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
converted: &ManiaBeatmap<'_>,
) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted)
}
fn strains(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self::Strains {
fn strains(difficulty: &Difficulty, converted: &ManiaBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted)
}
@@ -59,14 +59,14 @@ impl IGameMode for Mania {
}
fn gradual_difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &ManiaBeatmap<'_>,
) -> Self::GradualDifficulty {
ManiaGradualDifficulty::new(difficulty, map)
}
fn gradual_performance(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &ManiaBeatmap<'_>,
) -> Self::GradualPerformance {
ManiaGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{
mania::{ManiaBeatmap, ManiaGradualDifficulty},
ModeDifficulty,
Difficulty,
};
use super::{ManiaPerformanceAttributes, ManiaScoreState};
@@ -20,14 +20,14 @@ use super::{ManiaPerformanceAttributes, ManiaScoreState};
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::mania::{Mania, ManiaGradualPerformance, ManiaScoreState};
///
/// let converted = Beatmap::from_path("./resources/1638954.osu")
/// .unwrap()
/// .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 state = ManiaScoreState::new(); // empty state, everything is on 0.
///
@@ -75,7 +75,7 @@ pub struct ManiaGradualPerformance {
impl ManiaGradualPerformance {
/// 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);
Self { difficulty }
@@ -129,7 +129,7 @@ mod tests {
.unchecked_into_converted::<Mania>();
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_2nd = ManiaGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -1,8 +1,7 @@
use std::cmp;
use crate::{
any::ModeDifficulty,
any::{HitResultPriority, ModeAttributeProvider},
any::{Difficulty, HitResultPriority, ModeAttributeProvider},
osu::OsuPerformance,
util::{map_or_attrs::MapOrAttrs, mods::Mods},
};
@@ -21,7 +20,7 @@ pub mod gradual;
#[must_use]
pub struct ManiaPerformance<'map> {
map_or_attrs: MapOrAttrs<'map, Mania>,
difficulty: ModeDifficulty,
difficulty: Difficulty,
n320: Option<u32>,
n300: Option<u32>,
n200: Option<u32>,
@@ -37,7 +36,7 @@ impl<'map> ManiaPerformance<'map> {
pub const fn new(map: ManiaBeatmap<'map>) -> Self {
Self {
map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
n320: None,
n300: None,
n200: None,
@@ -52,7 +51,7 @@ impl<'map> ManiaPerformance<'map> {
pub(crate) const fn from_mania_attributes(attrs: ManiaDifficultyAttributes) -> Self {
Self {
map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
n320: None,
n300: None,
n200: None,
@@ -192,7 +191,7 @@ impl<'map> ManiaPerformance<'map> {
pub fn generate_state(&mut self) -> ManiaScoreState {
let attrs = match self.map_or_attrs {
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)
}
@@ -718,7 +717,7 @@ impl<'map> ManiaPerformance<'map> {
let state = self.generate_state();
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,
};
@@ -731,10 +730,6 @@ impl<'map> ManiaPerformance<'map> {
inner.calculate()
}
fn generate_attributes(&self, map: &ManiaBeatmap<'_>) -> ManiaDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`ManiaPerformance`] through a [`ModeAttributeProvider`].
///
/// If you already calculated the attributes for the current map-mod
@@ -921,7 +916,7 @@ mod tests {
use proptest::prelude::*;
use crate::Beatmap;
use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*;
@@ -936,7 +931,7 @@ mod tests {
.unwrap()
.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);
+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;
@@ -16,7 +16,7 @@ impl ManiaStrains {
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);
ManiaStrains {
+7 -32
View File
@@ -1,5 +1,4 @@
use std::{
any,
borrow::Cow,
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
@@ -8,7 +7,8 @@ use std::{
use crate::{
model::mode::{ConvertStatus, IGameMode},
ModeDifficulty,
util::generic_fmt::GenericFormatter,
Difficulty,
};
use super::Beatmap;
@@ -74,13 +74,13 @@ impl<M: IGameMode> Converted<'_, M> {
}
/// Create a gradual difficulty calculator for the map.
pub fn gradual_difficulty(&self, difficulty: &ModeDifficulty) -> M::GradualDifficulty {
difficulty.gradual_difficulty(self)
pub fn gradual_difficulty(&self, difficulty: &Difficulty) -> M::GradualDifficulty {
M::gradual_difficulty(difficulty, self)
}
/// Create a gradual performance calculator for the map.
pub fn gradual_performance(&self, difficulty: &ModeDifficulty) -> M::GradualPerformance {
difficulty.gradual_performance(self)
pub fn gradual_performance(&self, difficulty: &Difficulty) -> M::GradualPerformance {
M::gradual_performance(difficulty, self)
}
}
@@ -189,34 +189,9 @@ impl<M> Clone for Converted<'_, M> {
impl<M> Debug for Converted<'_, M> {
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")
.field("map", &self.map)
.field("mode", &GenericFormatter::<M>::default())
.field("mode", &GenericFormatter::<M>::new())
.finish()
}
}
+4 -9
View File
@@ -7,7 +7,7 @@ use rosu_map::{
use crate::{
catch::Catch, mania::Mania, osu::Osu, taiko::Taiko, Difficulty, GradualDifficulty,
GradualPerformance, ModeDifficulty, Performance,
GradualPerformance, Performance,
};
pub use self::{
@@ -85,23 +85,18 @@ impl Beatmap {
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`].
pub const fn performance(&self) -> Performance<'_> {
Performance::new(self)
}
/// 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)
}
/// 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)
}
@@ -126,7 +121,7 @@ impl Beatmap {
}
/// 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
pub fn convert_inplace(&mut self, mode: GameMode) -> ConvertStatus {
+6 -8
View File
@@ -1,6 +1,6 @@
pub use rosu_map::section::general::GameMode;
use crate::any::ModeDifficulty;
use crate::Difficulty;
use super::beatmap::{Beatmap, Converted};
@@ -40,27 +40,25 @@ pub trait IGameMode: Sized {
/// Perform a difficulty calculation for a [`Converted`] beatmap and
/// process the final skill values.
fn difficulty(
difficulty: &ModeDifficulty,
map: &Converted<'_, Self>,
) -> Self::DifficultyAttributes;
fn difficulty(difficulty: &Difficulty, map: &Converted<'_, Self>)
-> Self::DifficultyAttributes;
/// Perform a difficulty calculation for a [`Converted`] beatmap without
/// 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.
fn performance(map: Converted<'_, Self>) -> Self::Performance<'_>;
/// Create a gradual difficulty calculator for a [`Converted`] beatmap.
fn gradual_difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &Converted<'_, Self>,
) -> Self::GradualDifficulty;
/// Create a gradual performance calculator for a [`Converted`] beatmap.
fn gradual_performance(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &Converted<'_, Self>,
) -> Self::GradualPerformance;
}
+8 -8
View File
@@ -8,7 +8,7 @@ use crate::{
OsuBeatmap,
},
util::mods::Mods,
ModeDifficulty,
Difficulty,
};
use self::osu_objects::OsuObjects;
@@ -31,14 +31,14 @@ use super::{
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::osu::{Osu, OsuGradualDifficulty};
///
/// let converted = Beatmap::from_path("./resources/2785319.osu")
/// .unwrap()
/// .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);
///
/// // the difficulty of the map after the first hit object
@@ -73,7 +73,7 @@ struct NotClonable;
impl OsuGradualDifficulty {
/// 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 clock_rate = difficulty.get_clock_rate();
@@ -262,7 +262,7 @@ mod osu_objects {
#[cfg(test)]
mod tests {
use crate::{osu::Osu, Beatmap};
use crate::{any::difficulty::converted::ConvertedDifficulty, osu::Osu, Beatmap};
use super::*;
@@ -272,7 +272,7 @@ mod tests {
.unwrap()
.unchecked_into_converted::<Osu>();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = OsuGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none());
@@ -284,7 +284,7 @@ mod tests {
.unwrap()
.unchecked_into_converted::<Osu>();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = 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);
}
let expected = ModeDifficulty::new()
let expected = ConvertedDifficulty::new()
.passed_objects(i as u32)
.calculate(&converted);
+5 -8
View File
@@ -1,7 +1,7 @@
use std::{cmp, pin::Pin};
use crate::{
any::difficulty::{mode::ModeDifficulty, skills::Skill},
any::difficulty::{skills::Skill, Difficulty},
model::beatmap::BeatmapAttributes,
osu::{
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_OUT_DURATION_MULTIPLIER: f64 = 0.3;
pub fn difficulty(
difficulty: &ModeDifficulty,
converted: &OsuBeatmap<'_>,
) -> OsuDifficultyAttributes {
pub fn difficulty(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> OsuDifficultyAttributes {
let DifficultyValues {
skills:
OsuSkills {
@@ -70,7 +67,7 @@ pub struct 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 clock_rate = difficulty.get_clock_rate();
@@ -106,7 +103,7 @@ pub struct 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 take = difficulty.get_passed_objects();
@@ -218,7 +215,7 @@ impl DifficultyValues {
}
pub fn create_difficulty_objects<'a>(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
scaling_factor: &ScalingFactor,
osu_objects: impl ExactSizeIterator<Item = Pin<&'a mut OsuObject>>,
) -> Vec<OsuDifficultyObject<'a>> {
+5 -5
View File
@@ -1,11 +1,11 @@
use rosu_map::util::Pos;
use crate::{
any::ModeDifficulty,
model::{
beatmap::Beatmap,
mode::{ConvertStatus, IGameMode},
},
Difficulty,
};
pub use self::{
@@ -48,13 +48,13 @@ impl IGameMode for Osu {
}
fn difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
converted: &OsuBeatmap<'_>,
) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted)
}
fn strains(difficulty: &ModeDifficulty, converted: &OsuBeatmap<'_>) -> Self::Strains {
fn strains(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted)
}
@@ -63,14 +63,14 @@ impl IGameMode for Osu {
}
fn gradual_difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &OsuBeatmap<'_>,
) -> Self::GradualDifficulty {
OsuGradualDifficulty::new(difficulty, map)
}
fn gradual_performance(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &OsuBeatmap<'_>,
) -> Self::GradualPerformance {
OsuGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{
osu::{OsuBeatmap, OsuGradualDifficulty},
ModeDifficulty,
Difficulty,
};
use super::{OsuPerformanceAttributes, OsuScoreState};
@@ -20,14 +20,14 @@ use super::{OsuPerformanceAttributes, OsuScoreState};
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::osu::{Osu, OsuGradualPerformance, OsuScoreState};
///
/// let converted = Beatmap::from_path("./resources/2785319.osu")
/// .unwrap()
/// .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 state = OsuScoreState::new(); // empty state, everything is on 0.
///
@@ -85,7 +85,7 @@ pub struct OsuGradualPerformance {
impl OsuGradualPerformance {
/// 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);
Self { difficulty }
@@ -139,7 +139,7 @@ mod tests {
.unchecked_into_converted::<Osu>();
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_2nd = OsuGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -3,8 +3,7 @@ use std::cmp;
use rosu_map::section::general::GameMode;
use crate::{
any::ModeDifficulty,
any::{HitResultPriority, ModeAttributeProvider, Performance},
any::{Difficulty, HitResultPriority, ModeAttributeProvider, Performance},
catch::CatchPerformance,
mania::ManiaPerformance,
taiko::TaikoPerformance,
@@ -25,7 +24,7 @@ pub mod gradual;
#[must_use]
pub struct OsuPerformance<'map> {
pub(crate) map_or_attrs: MapOrAttrs<'map, Osu>,
pub(crate) difficulty: ModeDifficulty,
pub(crate) difficulty: Difficulty,
pub(crate) acc: Option<f64>,
pub(crate) combo: Option<u32>,
pub(crate) n300: Option<u32>,
@@ -40,7 +39,7 @@ impl<'map> OsuPerformance<'map> {
pub const fn new(map: OsuBeatmap<'map>) -> Self {
Self {
map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
acc: None,
combo: None,
n300: None,
@@ -54,7 +53,7 @@ impl<'map> OsuPerformance<'map> {
pub(crate) const fn from_osu_attributes(attrs: OsuDifficultyAttributes) -> Self {
Self {
map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
acc: None,
combo: None,
n300: None,
@@ -233,7 +232,7 @@ impl<'map> OsuPerformance<'map> {
pub fn generate_state(&mut self) -> OsuScoreState {
let attrs = match self.map_or_attrs {
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)
}
@@ -417,7 +416,7 @@ impl<'map> OsuPerformance<'map> {
let state = self.generate_state();
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,
};
@@ -434,10 +433,6 @@ impl<'map> OsuPerformance<'map> {
inner.calculate()
}
fn generate_attributes(&self, map: &OsuBeatmap<'_>) -> OsuDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`OsuPerformance`] through a [`ModeAttributeProvider`].
///
/// If you already calculated the attributes for the current map-mod
@@ -828,7 +823,7 @@ mod test {
use proptest::prelude::*;
use crate::Beatmap;
use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*;
@@ -843,7 +838,7 @@ mod test {
.unwrap()
.unchecked_into_converted::<Osu>();
let attrs = ModeDifficulty::new().calculate(&converted);
let attrs = ConvertedDifficulty::new().calculate(&converted);
assert_eq!(
(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::{
convert::OsuBeatmap,
@@ -25,7 +25,7 @@ impl OsuStrains {
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 {
skills:
OsuSkills {
+8 -9
View File
@@ -4,7 +4,7 @@ use crate::{
model::{beatmap::HitWindows, hit_object::HitObject},
taiko::TaikoBeatmap,
util::sync::RefCount,
ModeDifficulty,
Difficulty,
};
use super::{
@@ -25,14 +25,14 @@ use super::{
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::taiko::{Taiko, TaikoGradualDifficulty};
///
/// let converted = Beatmap::from_path("./resources/1028484.osu")
/// .unwrap()
/// .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);
///
/// // the difficulty of the map after the first hit object
@@ -69,7 +69,7 @@ enum FirstTwoCombos {
impl TaikoGradualDifficulty {
/// 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 mods = difficulty.get_mods();
let clock_rate = difficulty.get_clock_rate();
@@ -260,8 +260,7 @@ impl ExactSizeIterator for TaikoGradualDifficulty {
#[cfg(test)]
mod tests {
use crate::Beatmap;
use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*;
@@ -269,7 +268,7 @@ mod tests {
fn empty() {
let converted = Beatmap::from_bytes(&[]).unwrap().unchecked_into_converted();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted);
assert!(gradual.next().is_none());
@@ -281,7 +280,7 @@ mod tests {
.unwrap()
.unchecked_into_converted();
let difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = 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);
}
let expected = ModeDifficulty::new()
let expected = ConvertedDifficulty::new()
.passed_objects(i as u32)
.calculate(&converted);
+3 -3
View File
@@ -1,5 +1,4 @@
use crate::{
any::difficulty::mode::ModeDifficulty,
taiko::{
difficulty::{
color::preprocessor::ColorDifficultyPreprocessor,
@@ -8,6 +7,7 @@ use crate::{
},
object::TaikoObject,
},
Difficulty,
};
use self::skills::peaks::Peaks;
@@ -23,7 +23,7 @@ mod skills;
const DIFFICULTY_MULTIPLIER: f64 = 1.35;
pub fn difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
converted: &TaikoBeatmap<'_>,
) -> TaikoDifficultyAttributes {
let clock_rate = difficulty.get_clock_rate();
@@ -74,7 +74,7 @@ pub struct 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 clock_rate = difficulty.get_clock_rate();
+5 -5
View File
@@ -1,9 +1,9 @@
use crate::{
any::ModeDifficulty,
model::{
beatmap::Beatmap,
mode::{ConvertStatus, IGameMode},
},
Difficulty,
};
pub use self::{
@@ -44,13 +44,13 @@ impl IGameMode for Taiko {
}
fn difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
converted: &TaikoBeatmap<'_>,
) -> Self::DifficultyAttributes {
difficulty::difficulty(difficulty, converted)
}
fn strains(difficulty: &ModeDifficulty, converted: &TaikoBeatmap<'_>) -> Self::Strains {
fn strains(difficulty: &Difficulty, converted: &TaikoBeatmap<'_>) -> Self::Strains {
strains::strains(difficulty, converted)
}
@@ -59,14 +59,14 @@ impl IGameMode for Taiko {
}
fn gradual_difficulty(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &TaikoBeatmap<'_>,
) -> Self::GradualDifficulty {
TaikoGradualDifficulty::new(difficulty, map)
}
fn gradual_performance(
difficulty: &ModeDifficulty,
difficulty: &Difficulty,
map: &TaikoBeatmap<'_>,
) -> Self::GradualPerformance {
TaikoGradualPerformance::new(difficulty, map)
+5 -5
View File
@@ -1,6 +1,6 @@
use crate::{
taiko::{difficulty::gradual::TaikoGradualDifficulty, TaikoBeatmap, TaikoScoreState},
ModeDifficulty,
Difficulty,
};
use super::TaikoPerformanceAttributes;
@@ -20,14 +20,14 @@ use super::TaikoPerformanceAttributes;
/// # Example
///
/// ```
/// use rosu_pp::{Beatmap, ModeDifficulty};
/// use rosu_pp::{Beatmap, Difficulty};
/// use rosu_pp::taiko::{Taiko, TaikoGradualPerformance, TaikoScoreState};
///
/// let converted = Beatmap::from_path("./resources/1028484.osu")
/// .unwrap()
/// .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 state = TaikoScoreState::new(); // empty state, everything is on 0.
///
@@ -84,7 +84,7 @@ pub struct TaikoGradualPerformance {
impl TaikoGradualPerformance {
/// 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);
Self { difficulty }
@@ -135,7 +135,7 @@ mod tests {
.unchecked_into_converted();
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_2nd = TaikoGradualPerformance::new(&difficulty, &converted);
+8 -13
View File
@@ -1,8 +1,7 @@
use std::cmp;
use crate::{
any::ModeDifficulty,
any::{HitResultPriority, ModeAttributeProvider},
any::{Difficulty, HitResultPriority, ModeAttributeProvider},
osu::OsuPerformance,
util::{map_or_attrs::MapOrAttrs, mods::Mods},
};
@@ -21,7 +20,7 @@ pub mod gradual;
#[must_use]
pub struct TaikoPerformance<'map> {
pub(crate) map_or_attrs: MapOrAttrs<'map, Taiko>,
difficulty: ModeDifficulty,
difficulty: Difficulty,
combo: Option<u32>,
acc: Option<f64>,
hitresult_priority: HitResultPriority,
@@ -35,7 +34,7 @@ impl<'map> TaikoPerformance<'map> {
pub const fn new(map: TaikoBeatmap<'map>) -> Self {
Self {
map_or_attrs: MapOrAttrs::Map(map),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
combo: None,
acc: None,
misses: None,
@@ -48,7 +47,7 @@ impl<'map> TaikoPerformance<'map> {
pub(crate) const fn from_taiko_attributes(attrs: TaikoDifficultyAttributes) -> Self {
Self {
map_or_attrs: MapOrAttrs::Attrs(attrs),
difficulty: ModeDifficulty::new(),
difficulty: Difficulty::new(),
combo: None,
acc: None,
misses: None,
@@ -167,7 +166,7 @@ impl<'map> TaikoPerformance<'map> {
pub fn generate_state(&mut self) -> TaikoScoreState {
let attrs = match self.map_or_attrs {
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)
}
@@ -255,7 +254,7 @@ impl<'map> TaikoPerformance<'map> {
let state = self.generate_state();
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,
};
@@ -268,10 +267,6 @@ impl<'map> TaikoPerformance<'map> {
inner.calculate()
}
fn generate_attributes(&self, map: &TaikoBeatmap<'_>) -> TaikoDifficultyAttributes {
self.difficulty.calculate(map)
}
/// Try to create [`TaikoPerformance`] through a [`ModeAttributeProvider`].
///
/// If you already calculated the attributes for the current map-mod
@@ -506,7 +501,7 @@ mod test {
use proptest::prelude::*;
use crate::Beatmap;
use crate::{any::difficulty::converted::ConvertedDifficulty, Beatmap};
use super::*;
@@ -521,7 +516,7 @@ mod test {
.unwrap()
.unchecked_into_converted::<Taiko>();
let attrs = ModeDifficulty::new().calculate(&converted);
let attrs = ConvertedDifficulty::new().calculate(&converted);
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;
@@ -20,7 +20,7 @@ impl TaikoStrains {
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);
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 generic_fmt;
pub mod limited_queue;
pub mod map_or_attrs;
pub mod mods;
+4 -4
View File
@@ -133,10 +133,10 @@ impl<T: fmt::Debug> fmt::Debug for Weak<T> {
}
/// ```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 difficulty = ModeDifficulty::new();
/// let difficulty = Difficulty::new();
/// let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted);
///
/// // Rc<RefCell<_>> cannot be shared across threads so compilation should fail
@@ -149,10 +149,10 @@ const fn _share_gradual_taiko() {}
mod tests {
#[test]
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 difficulty = ModeDifficulty::new();
let difficulty = Difficulty::new();
let mut gradual = TaikoGradualDifficulty::new(&difficulty, &converted);
// 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},
osu::{Osu, OsuDifficultyAttributes},
taiko::{Taiko, TaikoDifficultyAttributes},
Beatmap, ModeDifficulty,
Beatmap, ConvertedDifficulty,
};
use self::common::*;
@@ -25,7 +25,7 @@ macro_rules! test_cases {
$(
let mods = 0 $( + $mods )*;
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);
)*
};