create perf calc either by map or attrs
This commit is contained in:
@@ -34,12 +34,10 @@ let diff_attrs = rosu_pp::Difficulty::new()
|
|||||||
let stars = diff_attrs.stars();
|
let stars = diff_attrs.stars();
|
||||||
|
|
||||||
// Calculate performance attributes
|
// Calculate performance attributes
|
||||||
let perf_attrs = map.performance()
|
let perf_attrs = rosu_pp::Performance::from_attributes(diff_attrs)
|
||||||
// To speed up the calculation, we can use the previous attributes.
|
// To speed up the calculation, we used the previous attributes.
|
||||||
// **Note** that this should only be done if the map and all difficulty
|
// **Note** that this should only be done if the map and all difficulty
|
||||||
// settings stay the same, otherwise the final attributes will be
|
// settings stay the same, otherwise the final attributes will be incorrect!
|
||||||
// incorrect!
|
|
||||||
.attributes(diff_attrs)
|
|
||||||
.mods(24) // HDHR, must be the same as before
|
.mods(24) // HDHR, must be the same as before
|
||||||
.combo(789)
|
.combo(789)
|
||||||
.accuracy(99.2)
|
.accuracy(99.2)
|
||||||
@@ -49,7 +47,6 @@ let perf_attrs = map.performance()
|
|||||||
let pp = perf_attrs.pp();
|
let pp = perf_attrs.pp();
|
||||||
|
|
||||||
// Again, we re-use the previous attributes for maximum efficiency.
|
// Again, we re-use the previous attributes for maximum efficiency.
|
||||||
// This time we do it directly instead of through the map.
|
|
||||||
let max_pp = perf_attrs.performance()
|
let max_pp = perf_attrs.performance()
|
||||||
.mods(24) // Still the same
|
.mods(24) // Still the same
|
||||||
.calculate()
|
.calculate()
|
||||||
|
|||||||
+4
-43
@@ -1,9 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
catch::{Catch, CatchDifficultyAttributes, CatchPerformanceAttributes},
|
catch::{CatchDifficultyAttributes, CatchPerformanceAttributes},
|
||||||
mania::{Mania, ManiaDifficultyAttributes, ManiaPerformanceAttributes},
|
mania::{ManiaDifficultyAttributes, ManiaPerformanceAttributes},
|
||||||
model::mode::IGameMode,
|
osu::{OsuDifficultyAttributes, OsuPerformanceAttributes},
|
||||||
osu::{Osu, OsuDifficultyAttributes, OsuPerformanceAttributes},
|
taiko::{TaikoDifficultyAttributes, TaikoPerformanceAttributes},
|
||||||
taiko::{Taiko, TaikoDifficultyAttributes, TaikoPerformanceAttributes},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::performance::Performance;
|
use super::performance::Performance;
|
||||||
@@ -137,18 +136,6 @@ impl AttributeProvider for PerformanceAttributes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
|
||||||
pub trait ModeAttributeProvider<M: IGameMode> {
|
|
||||||
/// Provide the actual difficulty attributes.
|
|
||||||
fn attributes(self) -> Option<M::DifficultyAttributes>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M: IGameMode> ModeAttributeProvider<M> for M::DifficultyAttributes {
|
|
||||||
fn attributes(self) -> Option<M::DifficultyAttributes> {
|
|
||||||
Some(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_attr_provider {
|
macro_rules! impl_attr_provider {
|
||||||
( $mode:ident: $difficulty:ident, $performance:ident ) => {
|
( $mode:ident: $difficulty:ident, $performance:ident ) => {
|
||||||
impl AttributeProvider for $difficulty {
|
impl AttributeProvider for $difficulty {
|
||||||
@@ -162,32 +149,6 @@ macro_rules! impl_attr_provider {
|
|||||||
DifficultyAttributes::$mode(self.difficulty)
|
DifficultyAttributes::$mode(self.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModeAttributeProvider<$mode> for $performance {
|
|
||||||
fn attributes(self) -> Option<<$mode as IGameMode>::DifficultyAttributes> {
|
|
||||||
Some(self.difficulty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModeAttributeProvider<$mode> for DifficultyAttributes {
|
|
||||||
fn attributes(self) -> Option<<$mode as IGameMode>::DifficultyAttributes> {
|
|
||||||
if let Self::$mode(attrs) = self {
|
|
||||||
Some(attrs)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModeAttributeProvider<$mode> for PerformanceAttributes {
|
|
||||||
fn attributes(self) -> Option<<$mode as IGameMode>::DifficultyAttributes> {
|
|
||||||
if let Self::$mode(attrs) = self {
|
|
||||||
Some(attrs.difficulty)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -1,7 +1,5 @@
|
|||||||
pub use self::{
|
pub use self::{
|
||||||
attributes::{
|
attributes::{AttributeProvider, DifficultyAttributes, PerformanceAttributes},
|
||||||
AttributeProvider, DifficultyAttributes, ModeAttributeProvider, PerformanceAttributes,
|
|
||||||
},
|
|
||||||
difficulty::{
|
difficulty::{
|
||||||
converted::ConvertedDifficulty, gradual::GradualDifficulty, inspect::InspectDifficulty,
|
converted::ConvertedDifficulty, gradual::GradualDifficulty, inspect::InspectDifficulty,
|
||||||
Difficulty, ModsDependent,
|
Difficulty, ModsDependent,
|
||||||
|
|||||||
+28
-34
@@ -31,25 +31,42 @@ pub enum Performance<'map> {
|
|||||||
|
|
||||||
impl<'map> Performance<'map> {
|
impl<'map> Performance<'map> {
|
||||||
/// Create a new performance calculator for maps of any mode.
|
/// Create a new performance calculator for maps of any mode.
|
||||||
pub const fn new(map: &'map Beatmap) -> Self {
|
///
|
||||||
|
/// Note that creating [`Performance`] this way will require to perform the
|
||||||
|
/// costly computation of difficulty attributes internally. If attributes
|
||||||
|
/// for the current [`Difficulty`] settings are already available, consider
|
||||||
|
/// using [`from_attributes`] instead.
|
||||||
|
///
|
||||||
|
/// [`from_attributes`]: Self::from_attributes
|
||||||
|
pub const fn from_map(map: &'map Beatmap) -> Self {
|
||||||
let mode = map.mode;
|
let mode = map.mode;
|
||||||
let map = Cow::Borrowed(map);
|
let map = Cow::Borrowed(map);
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
GameMode::Osu => Self::Osu(OsuPerformance::new(Converted::new(map))),
|
GameMode::Osu => Self::Osu(OsuPerformance::from_map(Converted::new(map))),
|
||||||
GameMode::Taiko => Self::Taiko(TaikoPerformance::new(Converted::new(map))),
|
GameMode::Taiko => Self::Taiko(TaikoPerformance::from_map(Converted::new(map))),
|
||||||
GameMode::Catch => Self::Catch(CatchPerformance::new(Converted::new(map))),
|
GameMode::Catch => Self::Catch(CatchPerformance::from_map(Converted::new(map))),
|
||||||
GameMode::Mania => Self::Mania(ManiaPerformance::new(Converted::new(map))),
|
GameMode::Mania => Self::Mania(ManiaPerformance::from_map(Converted::new(map))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new performance calculator through previously calculated
|
/// Create a new performance calculator through previously calculated
|
||||||
/// attributes.
|
/// attributes.
|
||||||
///
|
///
|
||||||
/// Note that the [`Beatmap`] and [`Difficulty`] should be the same as when
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
/// the attributes were calculated.
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
pub fn from_attributes(attributes: impl AttributeProvider) -> Self {
|
/// incorrect.
|
||||||
Self::from(attributes)
|
pub fn from_attributes(attrs: impl AttributeProvider) -> Self {
|
||||||
|
const fn inner(attrs: DifficultyAttributes) -> Performance<'static> {
|
||||||
|
match attrs {
|
||||||
|
DifficultyAttributes::Osu(attrs) => Performance::Osu(attrs.performance()),
|
||||||
|
DifficultyAttributes::Taiko(attrs) => Performance::Taiko(attrs.performance()),
|
||||||
|
DifficultyAttributes::Catch(attrs) => Performance::Catch(attrs.performance()),
|
||||||
|
DifficultyAttributes::Mania(attrs) => Performance::Mania(attrs.performance()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner(attrs.attributes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the performance calculator and calculate
|
/// Consume the performance calculator and calculate
|
||||||
@@ -63,25 +80,11 @@ impl<'map> Performance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of a previous difficulty or performance calculation.
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current [`Beatmap`]
|
|
||||||
/// and [`Difficulty`], be sure to put them in here so that they don't have
|
|
||||||
/// to be recalculated.
|
|
||||||
pub fn attributes(self, attributes: impl AttributeProvider) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Osu(o) => Self::Osu(o.attributes(attributes.attributes())),
|
|
||||||
Self::Taiko(t) => Self::Taiko(t.attributes(attributes.attributes())),
|
|
||||||
Self::Catch(f) => Self::Catch(f.attributes(attributes.attributes())),
|
|
||||||
Self::Mania(m) => Self::Mania(m.attributes(attributes.attributes())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to convert the map to the specified mode.
|
/// Attempt to convert the map to the specified mode.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the conversion is incompatible or the internal
|
/// Returns `None` if the conversion is incompatible or the internal
|
||||||
/// beatmap was already replaced with difficulty attributes, i.e. if
|
/// beatmap was already replaced with difficulty attributes, i.e. if
|
||||||
/// [`Performance::attributes`] or [`Performance::generate_state`] was
|
/// [`Performance::from_attributes`] or [`Performance::generate_state`] was
|
||||||
/// called.
|
/// called.
|
||||||
///
|
///
|
||||||
/// If the given mode should be ignored in case it is incompatible or if
|
/// If the given mode should be ignored in case it is incompatible or if
|
||||||
@@ -377,16 +380,7 @@ impl<'map> Performance<'map> {
|
|||||||
|
|
||||||
impl<A: AttributeProvider> From<A> for Performance<'_> {
|
impl<A: AttributeProvider> From<A> for Performance<'_> {
|
||||||
fn from(attrs: A) -> Self {
|
fn from(attrs: A) -> Self {
|
||||||
const fn inner(attrs: DifficultyAttributes) -> Performance<'static> {
|
Self::from_attributes(attrs)
|
||||||
match attrs {
|
|
||||||
DifficultyAttributes::Osu(attrs) => Performance::Osu(attrs.performance()),
|
|
||||||
DifficultyAttributes::Taiko(attrs) => Performance::Taiko(attrs.performance()),
|
|
||||||
DifficultyAttributes::Catch(attrs) => Performance::Catch(attrs.performance()),
|
|
||||||
DifficultyAttributes::Mania(attrs) => Performance::Mania(attrs.performance()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner(attrs.attributes())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ impl CatchDifficultyAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> CatchPerformance<'a> {
|
pub const fn performance<'a>(self) -> CatchPerformance<'a> {
|
||||||
CatchPerformance::from_catch_attributes(self)
|
CatchPerformance::from_attributes(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_object_count(&mut self, count: &ObjectCount) {
|
pub(crate) fn set_object_count(&mut self, count: &ObjectCount) {
|
||||||
@@ -90,7 +90,7 @@ impl CatchPerformanceAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> CatchPerformance<'a> {
|
pub const fn performance<'a>(self) -> CatchPerformance<'a> {
|
||||||
CatchPerformance::from_catch_attributes(self.difficulty)
|
CatchPerformance::from_attributes(self.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ impl IGameMode for Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn performance(map: CatchBeatmap<'_>) -> Self::Performance<'_> {
|
fn performance(map: CatchBeatmap<'_>) -> Self::Performance<'_> {
|
||||||
CatchPerformance::new(map)
|
CatchPerformance::from_map(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gradual_difficulty(
|
fn gradual_difficulty(
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ mod tests {
|
|||||||
assert_eq!(next_gradual, next_gradual_3rd);
|
assert_eq!(next_gradual, next_gradual_3rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
let regular_calc = CatchPerformance::new(converted.as_owned())
|
let regular_calc = CatchPerformance::from_map(converted.as_owned())
|
||||||
.difficulty(difficulty.clone())
|
.difficulty(difficulty.clone())
|
||||||
.passed_objects(i as u32)
|
.passed_objects(i as u32)
|
||||||
.state(state.clone());
|
.state(state.clone());
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::cmp::{self, Ordering};
|
use std::cmp::{self, Ordering};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
any::{Difficulty, ModeAttributeProvider},
|
any::{AttributeProvider, Difficulty, DifficultyAttributes},
|
||||||
osu::OsuPerformance,
|
osu::OsuPerformance,
|
||||||
util::{map_or_attrs::MapOrAttrs, mods::Mods},
|
util::{map_or_attrs::MapOrAttrs, mods::Mods},
|
||||||
};
|
};
|
||||||
@@ -32,7 +32,16 @@ pub struct CatchPerformance<'map> {
|
|||||||
|
|
||||||
impl<'map> CatchPerformance<'map> {
|
impl<'map> CatchPerformance<'map> {
|
||||||
/// Create a new performance calculator for osu!catch maps.
|
/// Create a new performance calculator for osu!catch maps.
|
||||||
pub const fn new(map: CatchBeatmap<'map>) -> Self {
|
///
|
||||||
|
/// Note that creating [`CatchPerformance`] this way will require to
|
||||||
|
/// perform the costly computation of [`CatchDifficultyAttributes`]
|
||||||
|
/// internally. If difficulty attributes for the current [`Difficulty`]
|
||||||
|
/// settings are already available, consider using [`from_attributes`] or
|
||||||
|
/// [`try_from_attributes`] instead.
|
||||||
|
///
|
||||||
|
/// [`from_attributes`]: Self::from_attributes
|
||||||
|
/// [`try_from_attributes`]: Self::try_from_attributes
|
||||||
|
pub const fn from_map(map: CatchBeatmap<'map>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Map(map),
|
map_or_attrs: MapOrAttrs::Map(map),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -46,7 +55,12 @@ impl<'map> CatchPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn from_catch_attributes(attrs: CatchDifficultyAttributes) -> Self {
|
/// Create a new performance calculator from difficulty attributes.
|
||||||
|
///
|
||||||
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
|
/// incorrect.
|
||||||
|
pub const fn from_attributes(attrs: CatchDifficultyAttributes) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -60,17 +74,19 @@ impl<'map> CatchPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of a previous difficulty or performance calculation.
|
/// Try to create a new performance calculator from difficulty attributes.
|
||||||
///
|
///
|
||||||
/// If you already calculated the attributes for the current
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
/// [`CatchBeatmap`] and [`Difficulty`], be sure to put them in here so
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
/// that they don't have to be recalculated.
|
/// incorrect.
|
||||||
pub fn attributes(mut self, attributes: impl ModeAttributeProvider<Catch>) -> Self {
|
///
|
||||||
if let Some(attrs) = attributes.attributes() {
|
/// Returns `None` if `attrs` contained attributes of a different mode.
|
||||||
self.map_or_attrs = MapOrAttrs::Attrs(attrs);
|
pub fn try_from_attributes(attrs: impl AttributeProvider) -> Option<Self> {
|
||||||
|
if let DifficultyAttributes::Catch(attrs) = attrs.attributes() {
|
||||||
|
Some(Self::from_attributes(attrs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify mods through their bit values.
|
/// Specify mods through their bit values.
|
||||||
@@ -419,38 +435,6 @@ impl<'map> CatchPerformance<'map> {
|
|||||||
|
|
||||||
inner.calculate()
|
inner.calculate()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to create [`CatchPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`CatchBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`CatchPerformance::new`].
|
|
||||||
///
|
|
||||||
/// Returns `None` only if the [`ModeAttributeProvider`] did not contain
|
|
||||||
/// attributes for catch e.g. if it's [`DifficultyAttributes::Taiko`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Taiko`]: crate::any::DifficultyAttributes::Taiko
|
|
||||||
pub fn try_from_attributes(attributes: impl ModeAttributeProvider<Catch>) -> Option<Self> {
|
|
||||||
attributes.attributes().map(Self::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create [`CatchPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`CatchBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`CatchPerformance::new`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the [`ModeAttributeProvider`] did not contain attributes for
|
|
||||||
/// catch e.g. if it's [`DifficultyAttributes::Taiko`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Taiko`]: crate::any::DifficultyAttributes::Taiko
|
|
||||||
pub fn unchecked_from_attributes(attributes: impl ModeAttributeProvider<Catch>) -> Self {
|
|
||||||
Self::try_from_attributes(attributes).expect("invalid catch attributes")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'map> TryFrom<OsuPerformance<'map>> for CatchPerformance<'map> {
|
impl<'map> TryFrom<OsuPerformance<'map>> for CatchPerformance<'map> {
|
||||||
@@ -460,7 +444,7 @@ impl<'map> TryFrom<OsuPerformance<'map>> for CatchPerformance<'map> {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if [`OsuPerformance`] already replaced its internal
|
/// Returns `None` if [`OsuPerformance`] already replaced its internal
|
||||||
/// beatmap with [`OsuDifficultyAttributes`], i.e. if
|
/// beatmap with [`OsuDifficultyAttributes`], i.e. if
|
||||||
/// [`OsuPerformance::attributes`] or [`OsuPerformance::generate_state`]
|
/// [`OsuPerformance::from_attributes`] or [`OsuPerformance::generate_state`]
|
||||||
/// was called.
|
/// was called.
|
||||||
///
|
///
|
||||||
/// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes
|
/// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes
|
||||||
@@ -506,19 +490,19 @@ impl<'map> TryFrom<OsuPerformance<'map>> for CatchPerformance<'map> {
|
|||||||
|
|
||||||
impl<'map> From<CatchBeatmap<'map>> for CatchPerformance<'map> {
|
impl<'map> From<CatchBeatmap<'map>> for CatchPerformance<'map> {
|
||||||
fn from(map: CatchBeatmap<'map>) -> Self {
|
fn from(map: CatchBeatmap<'map>) -> Self {
|
||||||
Self::new(map)
|
Self::from_map(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CatchDifficultyAttributes> for CatchPerformance<'_> {
|
impl From<CatchDifficultyAttributes> for CatchPerformance<'_> {
|
||||||
fn from(attrs: CatchDifficultyAttributes) -> Self {
|
fn from(attrs: CatchDifficultyAttributes) -> Self {
|
||||||
Self::from_catch_attributes(attrs)
|
Self::from_attributes(attrs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CatchPerformanceAttributes> for CatchPerformance<'_> {
|
impl From<CatchPerformanceAttributes> for CatchPerformance<'_> {
|
||||||
fn from(attrs: CatchPerformanceAttributes) -> Self {
|
fn from(attrs: CatchPerformanceAttributes) -> Self {
|
||||||
Self::from_catch_attributes(attrs.difficulty)
|
Self::from_attributes(attrs.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-6
@@ -28,12 +28,10 @@
|
|||||||
//! let stars = diff_attrs.stars();
|
//! let stars = diff_attrs.stars();
|
||||||
//!
|
//!
|
||||||
//! // Calculate performance attributes
|
//! // Calculate performance attributes
|
||||||
//! let perf_attrs = map.performance()
|
//! let perf_attrs = rosu_pp::Performance::from_attributes(diff_attrs)
|
||||||
//! // To speed up the calculation, we can use the previous attributes.
|
//! // To speed up the calculation, we used the previous attributes.
|
||||||
//! // **Note** that this should only be done if the map and all difficulty
|
//! // **Note** that this should only be done if the map and all difficulty
|
||||||
//! // settings stay the same, otherwise the final attributes will be
|
//! // settings stay the same, otherwise the final attributes will be incorrect!
|
||||||
//! // incorrect!
|
|
||||||
//! .attributes(diff_attrs)
|
|
||||||
//! .mods(24) // HDHR, must be the same as before
|
//! .mods(24) // HDHR, must be the same as before
|
||||||
//! .combo(789)
|
//! .combo(789)
|
||||||
//! .accuracy(99.2)
|
//! .accuracy(99.2)
|
||||||
@@ -43,7 +41,6 @@
|
|||||||
//! let pp = perf_attrs.pp();
|
//! let pp = perf_attrs.pp();
|
||||||
//!
|
//!
|
||||||
//! // Again, we re-use the previous attributes for maximum efficiency.
|
//! // Again, we re-use the previous attributes for maximum efficiency.
|
||||||
//! // This time we do it directly instead of through the map.
|
|
||||||
//! let max_pp = perf_attrs.performance()
|
//! let max_pp = perf_attrs.performance()
|
||||||
//! .mods(24) // Still the same
|
//! .mods(24) // Still the same
|
||||||
//! .calculate()
|
//! .calculate()
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ impl ManiaDifficultyAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> ManiaPerformance<'a> {
|
pub const fn performance<'a>(self) -> ManiaPerformance<'a> {
|
||||||
ManiaPerformance::from_mania_attributes(self)
|
ManiaPerformance::from_attributes(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ impl ManiaPerformanceAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> ManiaPerformance<'a> {
|
pub const fn performance<'a>(self) -> ManiaPerformance<'a> {
|
||||||
ManiaPerformance::from_mania_attributes(self.difficulty)
|
ManiaPerformance::from_attributes(self.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ impl IGameMode for Mania {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn performance(map: ManiaBeatmap<'_>) -> Self::Performance<'_> {
|
fn performance(map: ManiaBeatmap<'_>) -> Self::Performance<'_> {
|
||||||
ManiaPerformance::new(map)
|
ManiaPerformance::from_map(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gradual_difficulty(
|
fn gradual_difficulty(
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ mod tests {
|
|||||||
assert_eq!(next_gradual, next_gradual_3rd);
|
assert_eq!(next_gradual, next_gradual_3rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut regular_calc = ManiaPerformance::new(converted.as_owned())
|
let mut regular_calc = ManiaPerformance::from_map(converted.as_owned())
|
||||||
.difficulty(difficulty.clone())
|
.difficulty(difficulty.clone())
|
||||||
.passed_objects(i as u32)
|
.passed_objects(i as u32)
|
||||||
.state(state.clone());
|
.state(state.clone());
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
any::{Difficulty, HitResultPriority, ModeAttributeProvider},
|
any::{AttributeProvider, Difficulty, DifficultyAttributes, HitResultPriority},
|
||||||
osu::OsuPerformance,
|
osu::OsuPerformance,
|
||||||
util::{map_or_attrs::MapOrAttrs, mods::Mods},
|
util::{map_or_attrs::MapOrAttrs, mods::Mods},
|
||||||
};
|
};
|
||||||
@@ -33,7 +33,16 @@ pub struct ManiaPerformance<'map> {
|
|||||||
|
|
||||||
impl<'map> ManiaPerformance<'map> {
|
impl<'map> ManiaPerformance<'map> {
|
||||||
/// Create a new performance calculator for osu!mania maps.
|
/// Create a new performance calculator for osu!mania maps.
|
||||||
pub const fn new(map: ManiaBeatmap<'map>) -> Self {
|
///
|
||||||
|
/// Note that creating [`ManiaPerformance`] this way will require to
|
||||||
|
/// perform the costly computation of [`ManiaDifficultyAttributes`]
|
||||||
|
/// internally. If difficulty attributes for the current [`Difficulty`]
|
||||||
|
/// settings are already available, consider using [`from_attributes`] or
|
||||||
|
/// [`try_from_attributes`] instead.
|
||||||
|
///
|
||||||
|
/// [`from_attributes`]: Self::from_attributes
|
||||||
|
/// [`try_from_attributes`]: Self::try_from_attributes
|
||||||
|
pub const fn from_map(map: ManiaBeatmap<'map>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Map(map),
|
map_or_attrs: MapOrAttrs::Map(map),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -48,7 +57,12 @@ impl<'map> ManiaPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn from_mania_attributes(attrs: ManiaDifficultyAttributes) -> Self {
|
/// Create a new performance calculator from difficulty attributes.
|
||||||
|
///
|
||||||
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
|
/// incorrect.
|
||||||
|
pub const fn from_attributes(attrs: ManiaDifficultyAttributes) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -63,17 +77,19 @@ impl<'map> ManiaPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of a previous difficulty or performance calculation.
|
/// Try to create a new performance calculator from difficulty attributes.
|
||||||
///
|
///
|
||||||
/// If you already calculated the attributes for the current
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
/// [`ManiaBeatmap`] and [`Difficulty`], be sure to put them in here so
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
/// that they don't have to be recalculated.
|
/// incorrect.
|
||||||
pub fn attributes(mut self, attrs: impl ModeAttributeProvider<Mania>) -> Self {
|
///
|
||||||
if let Some(attrs) = attrs.attributes() {
|
/// Returns `None` if `attrs` contained attributes of a different mode.
|
||||||
self.map_or_attrs = MapOrAttrs::Attrs(attrs);
|
pub fn try_from_attributes(attrs: impl AttributeProvider) -> Option<Self> {
|
||||||
|
if let DifficultyAttributes::Mania(attrs) = attrs.attributes() {
|
||||||
|
Some(Self::from_attributes(attrs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify mods through their bit values.
|
/// Specify mods through their bit values.
|
||||||
@@ -773,38 +789,6 @@ impl<'map> ManiaPerformance<'map> {
|
|||||||
|
|
||||||
inner.calculate()
|
inner.calculate()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to create [`ManiaPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`ManiaBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`ManiaPerformance::new`].
|
|
||||||
///
|
|
||||||
/// Returns `None` only if the [`ModeAttributeProvider`] did not contain
|
|
||||||
/// attributes for mania e.g. if it's [`DifficultyAttributes::Taiko`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Taiko`]: crate::any::DifficultyAttributes::Taiko
|
|
||||||
pub fn try_from_attributes(attributes: impl ModeAttributeProvider<Mania>) -> Option<Self> {
|
|
||||||
attributes.attributes().map(Self::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create [`ManiaPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`ManiaBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`ManiaPerformance::new`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the [`ModeAttributeProvider`] did not contain attributes for
|
|
||||||
/// catch e.g. if it's [`DifficultyAttributes::Taiko`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Taiko`]: crate::any::DifficultyAttributes::Taiko
|
|
||||||
pub fn unchecked_from_attributes(attributes: impl ModeAttributeProvider<Mania>) -> Self {
|
|
||||||
Self::try_from_attributes(attributes).expect("invalid mania attributes")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'map> TryFrom<OsuPerformance<'map>> for ManiaPerformance<'map> {
|
impl<'map> TryFrom<OsuPerformance<'map>> for ManiaPerformance<'map> {
|
||||||
@@ -814,7 +798,7 @@ impl<'map> TryFrom<OsuPerformance<'map>> for ManiaPerformance<'map> {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if [`OsuPerformance`] already replaced its internal
|
/// Returns `None` if [`OsuPerformance`] already replaced its internal
|
||||||
/// beatmap with [`OsuDifficultyAttributes`], i.e. if
|
/// beatmap with [`OsuDifficultyAttributes`], i.e. if
|
||||||
/// [`OsuPerformance::attributes`] or [`OsuPerformance::generate_state`]
|
/// [`OsuPerformance::from_attributes`] or [`OsuPerformance::generate_state`]
|
||||||
/// was called.
|
/// was called.
|
||||||
///
|
///
|
||||||
/// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes
|
/// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes
|
||||||
@@ -861,19 +845,19 @@ impl<'map> TryFrom<OsuPerformance<'map>> for ManiaPerformance<'map> {
|
|||||||
|
|
||||||
impl<'map> From<ManiaBeatmap<'map>> for ManiaPerformance<'map> {
|
impl<'map> From<ManiaBeatmap<'map>> for ManiaPerformance<'map> {
|
||||||
fn from(map: ManiaBeatmap<'map>) -> Self {
|
fn from(map: ManiaBeatmap<'map>) -> Self {
|
||||||
Self::new(map)
|
Self::from_map(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ManiaDifficultyAttributes> for ManiaPerformance<'_> {
|
impl From<ManiaDifficultyAttributes> for ManiaPerformance<'_> {
|
||||||
fn from(attrs: ManiaDifficultyAttributes) -> Self {
|
fn from(attrs: ManiaDifficultyAttributes) -> Self {
|
||||||
Self::from_mania_attributes(attrs)
|
Self::from_attributes(attrs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ManiaPerformanceAttributes> for ManiaPerformance<'_> {
|
impl From<ManiaPerformanceAttributes> for ManiaPerformance<'_> {
|
||||||
fn from(attrs: ManiaPerformanceAttributes) -> Self {
|
fn from(attrs: ManiaPerformanceAttributes) -> Self {
|
||||||
Self::from_mania_attributes(attrs.difficulty)
|
Self::from_attributes(attrs.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ impl Beatmap {
|
|||||||
|
|
||||||
/// 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::from_map(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a gradual difficulty calculator for this [`Beatmap`].
|
/// Create a gradual difficulty calculator for this [`Beatmap`].
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ impl OsuDifficultyAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> OsuPerformance<'a> {
|
pub const fn performance<'a>(self) -> OsuPerformance<'a> {
|
||||||
OsuPerformance::from_osu_attributes(self)
|
OsuPerformance::from_attributes(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ impl OsuPerformanceAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> OsuPerformance<'a> {
|
pub const fn performance<'a>(self) -> OsuPerformance<'a> {
|
||||||
OsuPerformance::from_osu_attributes(self.difficulty)
|
OsuPerformance::from_attributes(self.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ impl IGameMode for Osu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn performance(map: OsuBeatmap<'_>) -> Self::Performance<'_> {
|
fn performance(map: OsuBeatmap<'_>) -> Self::Performance<'_> {
|
||||||
OsuPerformance::new(map)
|
OsuPerformance::from_map(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gradual_difficulty(difficulty: Difficulty, map: &OsuBeatmap<'_>) -> Self::GradualDifficulty {
|
fn gradual_difficulty(difficulty: Difficulty, map: &OsuBeatmap<'_>) -> Self::GradualDifficulty {
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ mod tests {
|
|||||||
assert_eq!(next_gradual, next_gradual_3rd);
|
assert_eq!(next_gradual, next_gradual_3rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut regular_calc = OsuPerformance::new(converted.as_owned())
|
let mut regular_calc = OsuPerformance::from_map(converted.as_owned())
|
||||||
.difficulty(difficulty.clone())
|
.difficulty(difficulty.clone())
|
||||||
.passed_objects(i as u32)
|
.passed_objects(i as u32)
|
||||||
.state(state);
|
.state(state);
|
||||||
|
|||||||
+37
-52
@@ -3,7 +3,7 @@ use std::cmp;
|
|||||||
use rosu_map::section::general::GameMode;
|
use rosu_map::section::general::GameMode;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
any::{Difficulty, HitResultPriority, ModeAttributeProvider, Performance},
|
any::{AttributeProvider, Difficulty, DifficultyAttributes, HitResultPriority, Performance},
|
||||||
catch::CatchPerformance,
|
catch::CatchPerformance,
|
||||||
mania::ManiaPerformance,
|
mania::ManiaPerformance,
|
||||||
taiko::TaikoPerformance,
|
taiko::TaikoPerformance,
|
||||||
@@ -36,7 +36,16 @@ pub struct OsuPerformance<'map> {
|
|||||||
|
|
||||||
impl<'map> OsuPerformance<'map> {
|
impl<'map> OsuPerformance<'map> {
|
||||||
/// Create a new performance calculator for osu!standard maps.
|
/// Create a new performance calculator for osu!standard maps.
|
||||||
pub const fn new(map: OsuBeatmap<'map>) -> Self {
|
///
|
||||||
|
/// Note that creating [`OsuPerformance`] this way will require to
|
||||||
|
/// perform the costly computation of [`OsuDifficultyAttributes`]
|
||||||
|
/// internally. If difficulty attributes for the current [`Difficulty`]
|
||||||
|
/// settings are already available, consider using [`from_attributes`] or
|
||||||
|
/// [`try_from_attributes`] instead.
|
||||||
|
///
|
||||||
|
/// [`from_attributes`]: Self::from_attributes
|
||||||
|
/// [`try_from_attributes`]: Self::try_from_attributes
|
||||||
|
pub const fn from_map(map: OsuBeatmap<'map>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Map(map),
|
map_or_attrs: MapOrAttrs::Map(map),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -50,7 +59,12 @@ impl<'map> OsuPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn from_osu_attributes(attrs: OsuDifficultyAttributes) -> Self {
|
/// Create a new performance calculator from difficulty attributes.
|
||||||
|
///
|
||||||
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
|
/// incorrect.
|
||||||
|
pub const fn from_attributes(attrs: OsuDifficultyAttributes) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -64,10 +78,26 @@ impl<'map> OsuPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to create a new performance calculator from difficulty attributes.
|
||||||
|
///
|
||||||
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
|
/// incorrect.
|
||||||
|
///
|
||||||
|
/// Returns `None` if `attrs` contained attributes of a different mode.
|
||||||
|
pub fn try_from_attributes(attrs: impl AttributeProvider) -> Option<Self> {
|
||||||
|
if let DifficultyAttributes::Osu(attrs) = attrs.attributes() {
|
||||||
|
Some(Self::from_attributes(attrs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempt to convert the map to the specified mode.
|
/// Attempt to convert the map to the specified mode.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the internal beatmap was already replaced with
|
/// Returns `None` if the internal beatmap was already replaced with
|
||||||
/// [`OsuDifficultyAttributes`], i.e. if [`OsuPerformance::attributes`] or
|
/// [`OsuDifficultyAttributes`], i.e. if
|
||||||
|
/// [`OsuPerformance::from_attributes`] or
|
||||||
/// [`OsuPerformance::generate_state`] was called.
|
/// [`OsuPerformance::generate_state`] was called.
|
||||||
///
|
///
|
||||||
/// If the given mode should be ignored in case the internal beatmap was
|
/// If the given mode should be ignored in case the internal beatmap was
|
||||||
@@ -113,19 +143,6 @@ impl<'map> OsuPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of a previous difficulty or performance calculation.
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current
|
|
||||||
/// [`OsuBeatmap`] and [`Difficulty`], be sure to put them in here so that
|
|
||||||
/// they don't have to be recalculated.
|
|
||||||
pub fn attributes(mut self, attributes: impl ModeAttributeProvider<Osu>) -> Self {
|
|
||||||
if let Some(attrs) = attributes.attributes() {
|
|
||||||
self.map_or_attrs = MapOrAttrs::Attrs(attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Specify mods through their bit values.
|
/// Specify mods through their bit values.
|
||||||
///
|
///
|
||||||
/// See <https://github.com/ppy/osu-api/wiki#mods>
|
/// See <https://github.com/ppy/osu-api/wiki#mods>
|
||||||
@@ -506,55 +523,23 @@ impl<'map> OsuPerformance<'map> {
|
|||||||
|
|
||||||
inner.calculate()
|
inner.calculate()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to create [`OsuPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`OsuBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`OsuPerformance::new`].
|
|
||||||
///
|
|
||||||
/// Returns `None` only if the [`ModeAttributeProvider`] did not contain
|
|
||||||
/// attributes for osu e.g. if it's [`DifficultyAttributes::Taiko`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Taiko`]: crate::any::DifficultyAttributes::Taiko
|
|
||||||
pub fn try_from_attributes(attributes: impl ModeAttributeProvider<Osu>) -> Option<Self> {
|
|
||||||
attributes.attributes().map(Self::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create [`OsuPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`OsuBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`OsuPerformance::new`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the [`ModeAttributeProvider`] did not contain attributes for
|
|
||||||
/// osu e.g. if it's [`DifficultyAttributes::Taiko`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Taiko`]: crate::any::DifficultyAttributes::Taiko
|
|
||||||
pub fn unchecked_from_attributes(attributes: impl ModeAttributeProvider<Osu>) -> Self {
|
|
||||||
Self::try_from_attributes(attributes).expect("invalid osu attributes")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'map> From<OsuBeatmap<'map>> for OsuPerformance<'map> {
|
impl<'map> From<OsuBeatmap<'map>> for OsuPerformance<'map> {
|
||||||
fn from(map: OsuBeatmap<'map>) -> Self {
|
fn from(map: OsuBeatmap<'map>) -> Self {
|
||||||
Self::new(map)
|
Self::from_map(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OsuDifficultyAttributes> for OsuPerformance<'_> {
|
impl From<OsuDifficultyAttributes> for OsuPerformance<'_> {
|
||||||
fn from(attrs: OsuDifficultyAttributes) -> Self {
|
fn from(attrs: OsuDifficultyAttributes) -> Self {
|
||||||
Self::from_osu_attributes(attrs)
|
Self::from_attributes(attrs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OsuPerformanceAttributes> for OsuPerformance<'_> {
|
impl From<OsuPerformanceAttributes> for OsuPerformance<'_> {
|
||||||
fn from(attrs: OsuPerformanceAttributes) -> Self {
|
fn from(attrs: OsuPerformanceAttributes) -> Self {
|
||||||
Self::from_osu_attributes(attrs.difficulty)
|
Self::from_attributes(attrs.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ impl TaikoDifficultyAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> TaikoPerformance<'a> {
|
pub const fn performance<'a>(self) -> TaikoPerformance<'a> {
|
||||||
TaikoPerformance::from_taiko_attributes(self)
|
TaikoPerformance::from_attributes(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ impl TaikoPerformanceAttributes {
|
|||||||
|
|
||||||
/// Returns a builder for performance calculation.
|
/// Returns a builder for performance calculation.
|
||||||
pub const fn performance<'a>(self) -> TaikoPerformance<'a> {
|
pub const fn performance<'a>(self) -> TaikoPerformance<'a> {
|
||||||
TaikoPerformance::from_taiko_attributes(self.difficulty)
|
TaikoPerformance::from_attributes(self.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ impl IGameMode for Taiko {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn performance(map: TaikoBeatmap<'_>) -> Self::Performance<'_> {
|
fn performance(map: TaikoBeatmap<'_>) -> Self::Performance<'_> {
|
||||||
TaikoPerformance::new(map)
|
TaikoPerformance::from_map(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gradual_difficulty(
|
fn gradual_difficulty(
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ mod tests {
|
|||||||
assert_eq!(next_gradual, next_gradual_3rd);
|
assert_eq!(next_gradual, next_gradual_3rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut regular_calc = TaikoPerformance::new(converted.as_owned())
|
let mut regular_calc = TaikoPerformance::from_map(converted.as_owned())
|
||||||
.difficulty(difficulty.clone())
|
.difficulty(difficulty.clone())
|
||||||
.passed_objects(i as u32)
|
.passed_objects(i as u32)
|
||||||
.state(state);
|
.state(state);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
any::{Difficulty, HitResultPriority, ModeAttributeProvider},
|
any::{AttributeProvider, Difficulty, DifficultyAttributes, HitResultPriority},
|
||||||
osu::OsuPerformance,
|
osu::OsuPerformance,
|
||||||
util::{map_or_attrs::MapOrAttrs, mods::Mods},
|
util::{map_or_attrs::MapOrAttrs, mods::Mods},
|
||||||
};
|
};
|
||||||
@@ -31,7 +31,16 @@ pub struct TaikoPerformance<'map> {
|
|||||||
|
|
||||||
impl<'map> TaikoPerformance<'map> {
|
impl<'map> TaikoPerformance<'map> {
|
||||||
/// Create a new performance calculator for osu!taiko maps.
|
/// Create a new performance calculator for osu!taiko maps.
|
||||||
pub const fn new(map: TaikoBeatmap<'map>) -> Self {
|
///
|
||||||
|
/// Note that creating [`TaikoPerformance`] this way will require to
|
||||||
|
/// perform the costly computation of [`TaikoDifficultyAttributes`]
|
||||||
|
/// internally. If difficulty attributes for the current [`Difficulty`]
|
||||||
|
/// settings are already available, consider using [`from_attributes`] or
|
||||||
|
/// [`try_from_attributes`] instead.
|
||||||
|
///
|
||||||
|
/// [`from_attributes`]: Self::from_attributes
|
||||||
|
/// [`try_from_attributes`]: Self::try_from_attributes
|
||||||
|
pub const fn from_map(map: TaikoBeatmap<'map>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Map(map),
|
map_or_attrs: MapOrAttrs::Map(map),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -44,7 +53,12 @@ impl<'map> TaikoPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn from_taiko_attributes(attrs: TaikoDifficultyAttributes) -> Self {
|
/// Create a new performance calculator from difficulty attributes.
|
||||||
|
///
|
||||||
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
|
/// incorrect.
|
||||||
|
pub const fn from_attributes(attrs: TaikoDifficultyAttributes) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
map_or_attrs: MapOrAttrs::Attrs(attrs),
|
||||||
difficulty: Difficulty::new(),
|
difficulty: Difficulty::new(),
|
||||||
@@ -57,17 +71,19 @@ impl<'map> TaikoPerformance<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of a previous difficulty or performance calculation.
|
/// Try to create a new performance calculator from difficulty attributes.
|
||||||
///
|
///
|
||||||
/// If you already calculated the attributes for the current
|
/// Note that `attrs` must have been calculated for the same beatmap and
|
||||||
/// [`TaikoBeatmap`] and [`Difficulty`], be sure to put them in here so
|
/// [`Difficulty`] settings, otherwise the final attributes will be
|
||||||
/// that they don't have to be recalculated.
|
/// incorrect.
|
||||||
pub fn attributes(mut self, attrs: impl ModeAttributeProvider<Taiko>) -> Self {
|
///
|
||||||
if let Some(attrs) = attrs.attributes() {
|
/// Returns `None` if `attrs` contained attributes of a different mode.
|
||||||
self.map_or_attrs = MapOrAttrs::Attrs(attrs);
|
pub fn try_from_attributes(attrs: impl AttributeProvider) -> Option<Self> {
|
||||||
|
if let DifficultyAttributes::Taiko(attrs) = attrs.attributes() {
|
||||||
|
Some(Self::from_attributes(attrs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify mods through their bit values.
|
/// Specify mods through their bit values.
|
||||||
@@ -310,38 +326,6 @@ impl<'map> TaikoPerformance<'map> {
|
|||||||
|
|
||||||
inner.calculate()
|
inner.calculate()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to create [`TaikoPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`TaikoBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`TaikoPerformance::new`].
|
|
||||||
///
|
|
||||||
/// Returns `None` only if the [`ModeAttributeProvider`] did not contain
|
|
||||||
/// attributes for taiko e.g. if it's [`DifficultyAttributes::Mania`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Mania`]: crate::any::DifficultyAttributes::Mania
|
|
||||||
pub fn try_from_attributes(attributes: impl ModeAttributeProvider<Taiko>) -> Option<Self> {
|
|
||||||
attributes.attributes().map(Self::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create [`TaikoPerformance`] through a [`ModeAttributeProvider`].
|
|
||||||
///
|
|
||||||
/// If you already calculated the attributes for the current map-mod
|
|
||||||
/// combination, the [`TaikoBeatmap`] is no longer necessary to calculate
|
|
||||||
/// performance attributes so this method can be used instead of
|
|
||||||
/// [`TaikoPerformance::new`].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the [`ModeAttributeProvider`] did not contain attributes for
|
|
||||||
/// taiko e.g. if it's [`DifficultyAttributes::Mania`].
|
|
||||||
///
|
|
||||||
/// [`DifficultyAttributes::Mania`]: crate::any::DifficultyAttributes::Mania
|
|
||||||
pub fn unchecked_from_attributes(attributes: impl ModeAttributeProvider<Taiko>) -> Self {
|
|
||||||
Self::try_from_attributes(attributes).expect("invalid taiko attributes")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'map> TryFrom<OsuPerformance<'map>> for TaikoPerformance<'map> {
|
impl<'map> TryFrom<OsuPerformance<'map>> for TaikoPerformance<'map> {
|
||||||
@@ -351,7 +335,7 @@ impl<'map> TryFrom<OsuPerformance<'map>> for TaikoPerformance<'map> {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if [`OsuPerformance`] already replaced its internal
|
/// Returns `None` if [`OsuPerformance`] already replaced its internal
|
||||||
/// beatmap with [`OsuDifficultyAttributes`], i.e. if
|
/// beatmap with [`OsuDifficultyAttributes`], i.e. if
|
||||||
/// [`OsuPerformance::attributes`] or [`OsuPerformance::generate_state`]
|
/// [`OsuPerformance::from_attributes`] or [`OsuPerformance::generate_state`]
|
||||||
/// was called.
|
/// was called.
|
||||||
///
|
///
|
||||||
/// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes
|
/// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes
|
||||||
@@ -396,19 +380,19 @@ impl<'map> TryFrom<OsuPerformance<'map>> for TaikoPerformance<'map> {
|
|||||||
|
|
||||||
impl<'map> From<TaikoBeatmap<'map>> for TaikoPerformance<'map> {
|
impl<'map> From<TaikoBeatmap<'map>> for TaikoPerformance<'map> {
|
||||||
fn from(map: TaikoBeatmap<'map>) -> Self {
|
fn from(map: TaikoBeatmap<'map>) -> Self {
|
||||||
Self::new(map)
|
Self::from_map(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TaikoDifficultyAttributes> for TaikoPerformance<'_> {
|
impl From<TaikoDifficultyAttributes> for TaikoPerformance<'_> {
|
||||||
fn from(attrs: TaikoDifficultyAttributes) -> Self {
|
fn from(attrs: TaikoDifficultyAttributes) -> Self {
|
||||||
Self::from_taiko_attributes(attrs)
|
Self::from_attributes(attrs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TaikoPerformanceAttributes> for TaikoPerformance<'_> {
|
impl From<TaikoPerformanceAttributes> for TaikoPerformance<'_> {
|
||||||
fn from(attrs: TaikoPerformanceAttributes) -> Self {
|
fn from(attrs: TaikoPerformanceAttributes) -> Self {
|
||||||
Self::from_taiko_attributes(attrs.difficulty)
|
Self::from_attributes(attrs.difficulty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user