added some convenience methods
This commit is contained in:
@@ -8,7 +8,7 @@ use crate::{
|
||||
mania::{ManiaBeatmap, ManiaGradualDifficulty},
|
||||
osu::{OsuBeatmap, OsuGradualDifficulty},
|
||||
taiko::{TaikoBeatmap, TaikoGradualDifficulty},
|
||||
Beatmap, Converted, ModeDifficulty,
|
||||
Beatmap, ModeDifficulty,
|
||||
};
|
||||
|
||||
/// Gradually calculate the difficulty attributes on maps of any mode.
|
||||
@@ -48,10 +48,10 @@ pub enum GradualDifficulty {
|
||||
}
|
||||
|
||||
macro_rules! from_converted {
|
||||
( $fn:ident, $mode:ident, $converted:ident, $gradual:ident ) => {
|
||||
( $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($gradual::new(difficulty, converted))
|
||||
Self::$mode(difficulty.gradual_difficulty(converted))
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -62,29 +62,23 @@ impl GradualDifficulty {
|
||||
let map = Cow::Borrowed(map);
|
||||
|
||||
match map.mode {
|
||||
GameMode::Osu => Self::Osu(OsuGradualDifficulty::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Taiko => Self::Taiko(TaikoGradualDifficulty::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Catch => Self::Catch(CatchGradualDifficulty::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Mania => Self::Mania(ManiaGradualDifficulty::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Osu => Self::Osu(difficulty.gradual_difficulty(&OsuBeatmap::new(map, false))),
|
||||
GameMode::Taiko => {
|
||||
Self::Taiko(difficulty.gradual_difficulty(&TaikoBeatmap::new(map, false)))
|
||||
}
|
||||
GameMode::Catch => {
|
||||
Self::Catch(difficulty.gradual_difficulty(&CatchBeatmap::new(map, false)))
|
||||
}
|
||||
GameMode::Mania => {
|
||||
Self::Mania(difficulty.gradual_difficulty(&ManiaBeatmap::new(map, false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
from_converted!(from_osu_map, Osu, OsuBeatmap, OsuGradualDifficulty);
|
||||
from_converted!(from_taiko_map, Taiko, TaikoBeatmap, TaikoGradualDifficulty);
|
||||
from_converted!(from_catch_map, Catch, CatchBeatmap, CatchGradualDifficulty);
|
||||
from_converted!(from_mania_map, Mania, ManiaBeatmap, ManiaGradualDifficulty);
|
||||
from_converted!(from_osu_map, Osu, OsuBeatmap);
|
||||
from_converted!(from_taiko_map, Taiko, TaikoBeatmap);
|
||||
from_converted!(from_catch_map, Catch, CatchBeatmap);
|
||||
from_converted!(from_mania_map, Mania, ManiaBeatmap);
|
||||
}
|
||||
|
||||
impl Iterator for GradualDifficulty {
|
||||
|
||||
@@ -56,6 +56,19 @@ impl ModeDifficulty {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{
|
||||
mania::{ManiaBeatmap, ManiaGradualPerformance},
|
||||
osu::{OsuBeatmap, OsuGradualPerformance},
|
||||
taiko::{TaikoBeatmap, TaikoGradualPerformance},
|
||||
Beatmap, Converted, ModeDifficulty,
|
||||
Beatmap, ModeDifficulty,
|
||||
};
|
||||
|
||||
/// Gradually calculate the performance attributes on maps of any mode.
|
||||
@@ -97,10 +97,10 @@ pub enum GradualPerformance {
|
||||
}
|
||||
|
||||
macro_rules! from_converted {
|
||||
( $fn:ident, $mode:ident, $converted:ident, $gradual:ident ) => {
|
||||
( $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($gradual::new(difficulty, converted))
|
||||
Self::$mode(difficulty.gradual_performance(converted))
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -111,29 +111,25 @@ impl GradualPerformance {
|
||||
let map = Cow::Borrowed(map);
|
||||
|
||||
match map.mode {
|
||||
GameMode::Osu => Self::Osu(OsuGradualPerformance::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Taiko => Self::Taiko(TaikoGradualPerformance::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Catch => Self::Catch(CatchGradualPerformance::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Mania => Self::Mania(ManiaGradualPerformance::new(
|
||||
difficulty,
|
||||
&Converted::new(map, false),
|
||||
)),
|
||||
GameMode::Osu => {
|
||||
Self::Osu(difficulty.gradual_performance(&OsuBeatmap::new(map, false)))
|
||||
}
|
||||
GameMode::Taiko => {
|
||||
Self::Taiko(difficulty.gradual_performance(&TaikoBeatmap::new(map, false)))
|
||||
}
|
||||
GameMode::Catch => {
|
||||
Self::Catch(difficulty.gradual_performance(&CatchBeatmap::new(map, false)))
|
||||
}
|
||||
GameMode::Mania => {
|
||||
Self::Mania(difficulty.gradual_performance(&ManiaBeatmap::new(map, false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
from_converted!(from_osu_map, Osu, OsuBeatmap, OsuGradualPerformance);
|
||||
from_converted!(from_taiko_map, Taiko, TaikoBeatmap, TaikoGradualPerformance);
|
||||
from_converted!(from_catch_map, Catch, CatchBeatmap, CatchGradualPerformance);
|
||||
from_converted!(from_mania_map, Mania, ManiaBeatmap, ManiaGradualPerformance);
|
||||
from_converted!(from_osu_map, Osu, OsuBeatmap);
|
||||
from_converted!(from_taiko_map, Taiko, TaikoBeatmap);
|
||||
from_converted!(from_catch_map, Catch, CatchBeatmap);
|
||||
from_converted!(from_mania_map, Mania, ManiaBeatmap);
|
||||
|
||||
/// Process the next hit object and calculate the performance attributes
|
||||
/// for the resulting score state.
|
||||
|
||||
@@ -288,25 +288,25 @@ impl<A: AttributeProvider> From<A> for Performance<'_> {
|
||||
}
|
||||
|
||||
macro_rules! impl_from_converted {
|
||||
( $mode:ident: $performance:ident ) => {
|
||||
( $mode:ident ) => {
|
||||
impl<'a> From<Converted<'a, $mode>> for Performance<'a> {
|
||||
fn from(converted: Converted<'a, $mode>) -> Self {
|
||||
Self::$mode($performance::new(converted))
|
||||
Self::$mode(converted.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a> From<&'b Converted<'a, $mode>> for Performance<'a> {
|
||||
fn from(converted: &'b Converted<'a, $mode>) -> Self {
|
||||
Self::$mode($performance::new(converted.as_owned()))
|
||||
Self::$mode(converted.as_owned().into())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_converted!(Osu: OsuPerformance);
|
||||
impl_from_converted!(Taiko: TaikoPerformance);
|
||||
impl_from_converted!(Catch: CatchPerformance);
|
||||
impl_from_converted!(Mania: ManiaPerformance);
|
||||
impl_from_converted!(Osu);
|
||||
impl_from_converted!(Taiko);
|
||||
impl_from_converted!(Catch);
|
||||
impl_from_converted!(Mania);
|
||||
|
||||
/// While generating remaining hitresults, decide how they should be distributed.
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||
|
||||
@@ -36,6 +36,9 @@ pub struct Catch;
|
||||
impl IGameMode for Catch {
|
||||
type DifficultyAttributes = CatchDifficultyAttributes;
|
||||
type Strains = CatchStrains;
|
||||
type Performance<'map> = CatchPerformance<'map>;
|
||||
type GradualDifficulty = CatchGradualDifficulty;
|
||||
type GradualPerformance = CatchGradualPerformance;
|
||||
|
||||
fn try_convert(map: &mut Cow<'_, Beatmap>) -> ConvertStatus {
|
||||
convert::try_convert(map)
|
||||
@@ -51,4 +54,22 @@ impl IGameMode for Catch {
|
||||
fn strains(difficulty: &ModeDifficulty, converted: &CatchBeatmap<'_>) -> Self::Strains {
|
||||
strains::strains(difficulty, converted)
|
||||
}
|
||||
|
||||
fn performance(map: CatchBeatmap<'_>) -> Self::Performance<'_> {
|
||||
CatchPerformance::new(map)
|
||||
}
|
||||
|
||||
fn gradual_difficulty(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &CatchBeatmap<'_>,
|
||||
) -> Self::GradualDifficulty {
|
||||
CatchGradualDifficulty::new(difficulty, map)
|
||||
}
|
||||
|
||||
fn gradual_performance(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &CatchBeatmap<'_>,
|
||||
) -> Self::GradualPerformance {
|
||||
CatchGradualPerformance::new(difficulty, map)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ pub struct Mania;
|
||||
impl IGameMode for Mania {
|
||||
type DifficultyAttributes = ManiaDifficultyAttributes;
|
||||
type Strains = ManiaStrains;
|
||||
type Performance<'map> = ManiaPerformance<'map>;
|
||||
type GradualDifficulty = ManiaGradualDifficulty;
|
||||
type GradualPerformance = ManiaGradualPerformance;
|
||||
|
||||
fn try_convert(map: &mut Cow<'_, Beatmap>) -> ConvertStatus {
|
||||
convert::try_convert(map)
|
||||
@@ -48,4 +51,22 @@ impl IGameMode for Mania {
|
||||
fn strains(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self::Strains {
|
||||
strains::strains(difficulty, converted)
|
||||
}
|
||||
|
||||
fn performance(map: ManiaBeatmap<'_>) -> Self::Performance<'_> {
|
||||
ManiaPerformance::new(map)
|
||||
}
|
||||
|
||||
fn gradual_difficulty(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &ManiaBeatmap<'_>,
|
||||
) -> Self::GradualDifficulty {
|
||||
ManiaGradualDifficulty::new(difficulty, map)
|
||||
}
|
||||
|
||||
fn gradual_performance(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &ManiaBeatmap<'_>,
|
||||
) -> Self::GradualPerformance {
|
||||
ManiaGradualPerformance::new(difficulty, map)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@ use std::{
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use crate::model::mode::{ConvertStatus, IGameMode};
|
||||
use crate::{
|
||||
model::mode::{ConvertStatus, IGameMode},
|
||||
ModeDifficulty,
|
||||
};
|
||||
|
||||
use super::{attributes::BeatmapAttributesBuilder, Beatmap};
|
||||
|
||||
@@ -43,6 +46,24 @@ impl<'a, M> Converted<'a, M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> Converted<'_, M> {
|
||||
/// Sum up the duration of all breaks (in milliseconds).
|
||||
pub fn total_break_time(&self) -> f64 {
|
||||
self.map.total_break_time()
|
||||
}
|
||||
|
||||
/// Returns a [`BeatmapAttributesBuilder`] to calculate modified beatmap
|
||||
/// attributes.
|
||||
pub fn attributes(&self) -> BeatmapAttributesBuilder {
|
||||
self.into()
|
||||
}
|
||||
|
||||
/// The beats per minute of the map.
|
||||
pub fn bpm(&self) -> f64 {
|
||||
self.map.bpm()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: IGameMode> Converted<'_, M> {
|
||||
/// Attempt to convert a [`Beatmap`] to the specified mode.
|
||||
///
|
||||
@@ -72,20 +93,14 @@ impl<M: IGameMode> Converted<'_, M> {
|
||||
Self::try_from_owned(map).unwrap_or_else(|_| panic!("{}", INCOMPATIBLE_MODES))
|
||||
}
|
||||
|
||||
/// Sum up the duration of all breaks (in milliseconds).
|
||||
pub fn total_break_time(&self) -> f64 {
|
||||
self.map.total_break_time()
|
||||
/// Create a gradual difficulty calculator for the map.
|
||||
pub fn gradual_difficulty(&self, difficulty: &ModeDifficulty) -> M::GradualDifficulty {
|
||||
difficulty.gradual_difficulty(self)
|
||||
}
|
||||
|
||||
/// Returns a [`BeatmapAttributesBuilder`] to calculate modified beatmap
|
||||
/// attributes.
|
||||
pub fn attributes(&self) -> BeatmapAttributesBuilder {
|
||||
self.into()
|
||||
}
|
||||
|
||||
/// The beats per minute of the map.
|
||||
pub fn bpm(&self) -> f64 {
|
||||
self.map.bpm()
|
||||
/// Create a gradual performance calculator for the map.
|
||||
pub fn gradual_performance(&self, difficulty: &ModeDifficulty) -> M::GradualPerformance {
|
||||
difficulty.gradual_performance(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +108,18 @@ impl<'a, M: IGameMode> Converted<'a, M> {
|
||||
/// Borrow the contained [`Beatmap`] to cheaply create a new owned
|
||||
/// [`Converted`].
|
||||
///
|
||||
/// This is the same as `.clone()` except cheap but its lifetime might be
|
||||
/// This is the same as `.clone()` except cheap - but its lifetime might be
|
||||
/// shorter.
|
||||
#[must_use]
|
||||
pub fn as_owned(&'a self) -> Self {
|
||||
Self::new(Cow::Borrowed(self.map.as_ref()), self.is_convert)
|
||||
}
|
||||
|
||||
/// Create a performance calculator for the map.
|
||||
pub fn performance(self) -> M::Performance<'a> {
|
||||
M::performance(self)
|
||||
}
|
||||
|
||||
/// Attempt to convert a [`&Beatmap`] to the specified mode.
|
||||
///
|
||||
/// If the conversion is incompatible, `None` is returned.
|
||||
|
||||
@@ -5,7 +5,7 @@ use rosu_map::{
|
||||
LATEST_FORMAT_VERSION,
|
||||
};
|
||||
|
||||
use crate::{Difficulty, Performance};
|
||||
use crate::{Difficulty, GradualDifficulty, GradualPerformance, ModeDifficulty, Performance};
|
||||
|
||||
pub use self::{
|
||||
attributes::{BeatmapAttributes, BeatmapAttributesBuilder, HitWindows},
|
||||
@@ -70,16 +70,26 @@ impl Beatmap {
|
||||
rosu_map::from_bytes(bytes)
|
||||
}
|
||||
|
||||
/// Create a new difficulty calculator for this [`Beatmap`].
|
||||
/// Create a difficulty calculator for this [`Beatmap`].
|
||||
pub fn difficulty(&self) -> Difficulty<'_> {
|
||||
Difficulty::new(self)
|
||||
}
|
||||
|
||||
/// Create a new performance calculator for this [`Beatmap`].
|
||||
/// Create a performance calculator for this [`Beatmap`].
|
||||
pub fn performance(&self) -> Performance<'_> {
|
||||
Performance::new(self)
|
||||
}
|
||||
|
||||
/// Create a gradual difficulty calculator for this [`Beatmap`].
|
||||
pub fn gradual_difficulty(&self, difficulty: &ModeDifficulty) -> GradualDifficulty {
|
||||
GradualDifficulty::new(difficulty, self)
|
||||
}
|
||||
|
||||
/// Create a gradual performance calculator for this [`Beatmap`].
|
||||
pub fn gradual_performance(&self, difficulty: &ModeDifficulty) -> GradualPerformance {
|
||||
GradualPerformance::new(difficulty, self)
|
||||
}
|
||||
|
||||
/// Finds the [`TimingPoint`] that is active at the given time.
|
||||
pub(crate) fn timing_point_at(&self, time: f64) -> Option<&TimingPoint> {
|
||||
timing_point_at(&self.timing_points, time)
|
||||
|
||||
@@ -22,6 +22,15 @@ pub trait IGameMode: Sized {
|
||||
/// The resulting type of a strain calculation.
|
||||
type Strains;
|
||||
|
||||
/// The type of a performance calculator.
|
||||
type Performance<'map>;
|
||||
|
||||
/// The type of a gradual difficulty calculator.
|
||||
type GradualDifficulty;
|
||||
|
||||
/// The type of a gradual performance calculator.
|
||||
type GradualPerformance;
|
||||
|
||||
/// Attempt to convert a beatmap.
|
||||
///
|
||||
/// In case [`ConvertStatus::Incompatible`] is returned, the map should
|
||||
@@ -38,6 +47,21 @@ pub trait IGameMode: Sized {
|
||||
/// Perform a difficulty calculation for a [`Converted`] beatmap without
|
||||
/// processing the final skill values.
|
||||
fn strains(difficulty: &ModeDifficulty, 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,
|
||||
map: &Converted<'_, Self>,
|
||||
) -> Self::GradualDifficulty;
|
||||
|
||||
/// Create a gradual performance calculator for a [`Converted`] beatmap.
|
||||
fn gradual_performance(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &Converted<'_, Self>,
|
||||
) -> Self::GradualPerformance;
|
||||
}
|
||||
|
||||
/// The status of a conversion through [`IGameMode::try_convert`].
|
||||
|
||||
@@ -37,6 +37,9 @@ pub struct Osu;
|
||||
impl IGameMode for Osu {
|
||||
type DifficultyAttributes = OsuDifficultyAttributes;
|
||||
type Strains = OsuStrains;
|
||||
type Performance<'map> = OsuPerformance<'map>;
|
||||
type GradualDifficulty = OsuGradualDifficulty;
|
||||
type GradualPerformance = OsuGradualPerformance;
|
||||
|
||||
fn try_convert(map: &mut Cow<'_, Beatmap>) -> ConvertStatus {
|
||||
convert::try_convert(map)
|
||||
@@ -52,4 +55,22 @@ impl IGameMode for Osu {
|
||||
fn strains(difficulty: &ModeDifficulty, converted: &OsuBeatmap<'_>) -> Self::Strains {
|
||||
strains::strains(difficulty, converted)
|
||||
}
|
||||
|
||||
fn performance(map: OsuBeatmap<'_>) -> Self::Performance<'_> {
|
||||
OsuPerformance::new(map)
|
||||
}
|
||||
|
||||
fn gradual_difficulty(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &OsuBeatmap<'_>,
|
||||
) -> Self::GradualDifficulty {
|
||||
OsuGradualDifficulty::new(difficulty, map)
|
||||
}
|
||||
|
||||
fn gradual_performance(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &OsuBeatmap<'_>,
|
||||
) -> Self::GradualPerformance {
|
||||
OsuGradualPerformance::new(difficulty, map)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ pub struct Taiko;
|
||||
impl IGameMode for Taiko {
|
||||
type DifficultyAttributes = TaikoDifficultyAttributes;
|
||||
type Strains = TaikoStrains;
|
||||
type Performance<'map> = TaikoPerformance<'map>;
|
||||
type GradualDifficulty = TaikoGradualDifficulty;
|
||||
type GradualPerformance = TaikoGradualPerformance;
|
||||
|
||||
fn try_convert(map: &mut Cow<'_, Beatmap>) -> ConvertStatus {
|
||||
convert::try_convert(map)
|
||||
@@ -48,4 +51,22 @@ impl IGameMode for Taiko {
|
||||
fn strains(difficulty: &ModeDifficulty, converted: &TaikoBeatmap<'_>) -> Self::Strains {
|
||||
strains::strains(difficulty, converted)
|
||||
}
|
||||
|
||||
fn performance(map: TaikoBeatmap<'_>) -> Self::Performance<'_> {
|
||||
TaikoPerformance::new(map)
|
||||
}
|
||||
|
||||
fn gradual_difficulty(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &TaikoBeatmap<'_>,
|
||||
) -> Self::GradualDifficulty {
|
||||
TaikoGradualDifficulty::new(difficulty, map)
|
||||
}
|
||||
|
||||
fn gradual_performance(
|
||||
difficulty: &ModeDifficulty,
|
||||
map: &TaikoBeatmap<'_>,
|
||||
) -> Self::GradualPerformance {
|
||||
TaikoGradualPerformance::new(difficulty, map)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user