added convert support (#12)
* added taiko conversion * finished converts * made clippy happy * optimized allocations for patterns * taiko convert fixes * added mode methods for osu calculators * from CRLF back to LF * updated changelog * updated readme * undo normal hitsound change * added edge_sounds to changelog
This commit is contained in:
+26
-7
@@ -3,12 +3,14 @@ mod gradual_performance;
|
||||
mod pp;
|
||||
mod strain;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub use gradual_difficulty::*;
|
||||
pub use gradual_performance::*;
|
||||
pub use pp::*;
|
||||
use strain::Strain;
|
||||
|
||||
use crate::{parse::HitObject, Beatmap, GameMode, Mods, Strains};
|
||||
use crate::{parse::HitObject, Beatmap, GameMode, Mods, OsuStars, Strains};
|
||||
|
||||
const SECTION_LEN: f64 = 400.0;
|
||||
const STAR_SCALING_FACTOR: f64 = 0.018;
|
||||
@@ -33,7 +35,7 @@ const STAR_SCALING_FACTOR: f64 = 0.018;
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ManiaStars<'map> {
|
||||
map: &'map Beatmap,
|
||||
map: Cow<'map, Beatmap>,
|
||||
mods: u32,
|
||||
passed_objects: Option<usize>,
|
||||
clock_rate: Option<f64>,
|
||||
@@ -44,7 +46,7 @@ impl<'map> ManiaStars<'map> {
|
||||
#[inline]
|
||||
pub fn new(map: &'map Beatmap) -> Self {
|
||||
Self {
|
||||
map,
|
||||
map: Cow::Borrowed(map),
|
||||
mods: 0,
|
||||
passed_objects: None,
|
||||
clock_rate: None,
|
||||
@@ -189,12 +191,9 @@ pub(crate) struct DifficultyHitObject<'o> {
|
||||
impl<'o> DifficultyHitObject<'o> {
|
||||
#[inline]
|
||||
fn new(base: &'o HitObject, prev: &'o HitObject, columns: f32, clock_rate: f64) -> Self {
|
||||
let x_divisor = 512.0 / columns;
|
||||
let column = (base.pos.x / x_divisor).floor().min(columns - 1.0) as usize;
|
||||
|
||||
Self {
|
||||
base,
|
||||
column,
|
||||
column: base.column(columns) as usize,
|
||||
delta: (base.start_time - prev.start_time) / clock_rate,
|
||||
start_time: base.start_time / clock_rate,
|
||||
}
|
||||
@@ -236,7 +235,27 @@ impl ManiaPerformanceAttributes {
|
||||
}
|
||||
|
||||
impl From<ManiaPerformanceAttributes> for ManiaDifficultyAttributes {
|
||||
#[inline]
|
||||
fn from(attributes: ManiaPerformanceAttributes) -> Self {
|
||||
attributes.difficulty
|
||||
}
|
||||
}
|
||||
|
||||
impl<'map> From<OsuStars<'map>> for ManiaStars<'map> {
|
||||
#[inline]
|
||||
fn from(osu: OsuStars<'map>) -> Self {
|
||||
let OsuStars {
|
||||
map,
|
||||
mods,
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
} = osu;
|
||||
|
||||
Self {
|
||||
map: map.convert_mode(GameMode::MNA),
|
||||
mods,
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+41
-5
@@ -1,5 +1,7 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::{ManiaDifficultyAttributes, ManiaPerformanceAttributes, ManiaStars};
|
||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
use crate::{Beatmap, DifficultyAttributes, GameMode, Mods, OsuPP, PerformanceAttributes};
|
||||
|
||||
/// Performance calculator on osu!mania maps.
|
||||
///
|
||||
@@ -31,7 +33,7 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct ManiaPP<'map> {
|
||||
map: &'map Beatmap,
|
||||
map: Cow<'map, Beatmap>,
|
||||
stars: Option<f64>,
|
||||
mods: u32,
|
||||
pub(crate) score: Option<f64>,
|
||||
@@ -44,7 +46,7 @@ impl<'map> ManiaPP<'map> {
|
||||
#[inline]
|
||||
pub fn new(map: &'map Beatmap) -> Self {
|
||||
Self {
|
||||
map,
|
||||
map: Cow::Borrowed(map),
|
||||
stars: None,
|
||||
mods: 0,
|
||||
score: None,
|
||||
@@ -112,7 +114,7 @@ impl<'map> ManiaPP<'map> {
|
||||
/// Calculate all performance related values, including pp and stars.
|
||||
pub fn calculate(self) -> ManiaPerformanceAttributes {
|
||||
let stars = self.stars.unwrap_or_else(|| {
|
||||
let mut calculator = ManiaStars::new(self.map).mods(self.mods);
|
||||
let mut calculator = ManiaStars::new(self.map.as_ref()).mods(self.mods);
|
||||
|
||||
if let Some(passed_objects) = self.passed_objects {
|
||||
calculator = calculator.passed_objects(passed_objects);
|
||||
@@ -154,7 +156,19 @@ impl<'map> ManiaPP<'map> {
|
||||
od *= 1.4;
|
||||
}
|
||||
|
||||
let hit_window = ((od * clock_rate).floor() / clock_rate).ceil();
|
||||
let hit_window = {
|
||||
let not_converted = matches!(self.map, Cow::Borrowed(_));
|
||||
|
||||
let value = if not_converted {
|
||||
od
|
||||
} else if self.map.od > 4.0 {
|
||||
34.0
|
||||
} else {
|
||||
47.0
|
||||
};
|
||||
|
||||
((value * clock_rate).floor() / clock_rate).ceil()
|
||||
};
|
||||
|
||||
let strain_value = self.compute_strain(scaled_score, stars);
|
||||
let acc_value = self.compute_accuracy_value(scaled_score, strain_value, hit_window);
|
||||
@@ -199,6 +213,28 @@ impl<'map> ManiaPP<'map> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'map> From<OsuPP<'map>> for ManiaPP<'map> {
|
||||
#[inline]
|
||||
fn from(osu: OsuPP<'map>) -> Self {
|
||||
let OsuPP {
|
||||
map,
|
||||
mods,
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
..
|
||||
} = osu;
|
||||
|
||||
Self {
|
||||
map: map.convert_mode(GameMode::MNA),
|
||||
stars: None,
|
||||
mods,
|
||||
score: None,
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||
pub trait ManiaAttributeProvider {
|
||||
/// Provide the star rating (only difficulty attribute for osu!mania).
|
||||
|
||||
Reference in New Issue
Block a user