restructure Difficulty and ModeDifficulty
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user