added some convenience methods

This commit is contained in:
MaxOhn
2024-02-26 17:10:54 +01:00
parent 8d2132c124
commit 1a5f9b9681
11 changed files with 211 additions and 70 deletions
+17 -23
View File
@@ -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 {
+13
View File
@@ -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
}
+19 -23
View File
@@ -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.
+7 -7
View File
@@ -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)]
+21
View File
@@ -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)
}
}
+21
View File
@@ -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)
}
}
+34 -14
View File
@@ -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.
+13 -3
View File
@@ -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)
+24
View File
@@ -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`].
+21
View File
@@ -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)
}
}
+21
View File
@@ -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)
}
}