renamed GameMode variants
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
- Slider velocity is now adjusted properly for taiko converts
|
- Slider velocity is now adjusted properly for taiko converts
|
||||||
- __Breaking changes:__
|
- __Breaking changes:__
|
||||||
- Replaced the simple `Strains` struct with a new struct `{Mode}Strains` that contains more detail w.r.t. the mode.
|
- Replaced the simple `Strains` struct with a new struct `{Mode}Strains` that contains more detail w.r.t. the mode.
|
||||||
|
- Renamed all `GameMode` variants to more idiomatic names
|
||||||
|
|
||||||
# v0.6.0 (2022-07-05)
|
# v0.6.0 (2022-07-05)
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ impl Beatmap {
|
|||||||
|
|
||||||
legacy_sort(&mut map.hit_objects);
|
legacy_sort(&mut map.hit_objects);
|
||||||
|
|
||||||
map.mode = GameMode::MNA;
|
map.mode = GameMode::Mania;
|
||||||
|
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ impl Beatmap {
|
|||||||
map.hit_objects
|
map.hit_objects
|
||||||
.sort_by(|p1, p2| p1.partial_cmp(p2).unwrap_or(Ordering::Equal));
|
.sort_by(|p1, p2| p1.partial_cmp(p2).unwrap_or(Ordering::Equal));
|
||||||
|
|
||||||
map.mode = GameMode::TKO;
|
map.mode = GameMode::Taiko;
|
||||||
|
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -132,9 +132,9 @@ impl Beatmap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
GameMode::STD | GameMode::CTB => Cow::Borrowed(self),
|
GameMode::Osu | GameMode::Catch => Cow::Borrowed(self),
|
||||||
GameMode::TKO => Cow::Owned(self.convert_to_taiko()),
|
GameMode::Taiko => Cow::Owned(self.convert_to_taiko()),
|
||||||
GameMode::MNA => Cow::Owned(self.convert_to_mania()),
|
GameMode::Mania => Cow::Owned(self.convert_to_mania()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -1,20 +1,19 @@
|
|||||||
/// The mode of a beatmap.
|
/// The mode of a beatmap.
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
|
||||||
pub enum GameMode {
|
pub enum GameMode {
|
||||||
/// osu!standard
|
/// osu!standard
|
||||||
STD = 0,
|
Osu = 0,
|
||||||
/// osu!taiko
|
/// osu!taiko
|
||||||
TKO = 1,
|
Taiko = 1,
|
||||||
/// osu!catch
|
/// osu!catch
|
||||||
CTB = 2,
|
Catch = 2,
|
||||||
/// osu!mania
|
/// osu!mania
|
||||||
MNA = 3,
|
Mania = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GameMode {
|
impl Default for GameMode {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::STD
|
Self::Osu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -53,10 +53,10 @@ impl<'map> GradualDifficultyAttributes<'map> {
|
|||||||
/// Create a new gradual difficulty calculator for maps of any mode.
|
/// Create a new gradual difficulty calculator for maps of any mode.
|
||||||
pub fn new(map: &'map Beatmap, mods: impl Mods) -> Self {
|
pub fn new(map: &'map Beatmap, mods: impl Mods) -> Self {
|
||||||
match map.mode {
|
match map.mode {
|
||||||
GameMode::STD => Self::Osu(OsuGradualDifficultyAttributes::new(map, mods)),
|
GameMode::Osu => Self::Osu(OsuGradualDifficultyAttributes::new(map, mods)),
|
||||||
GameMode::TKO => Self::Taiko(TaikoGradualDifficultyAttributes::new(map, mods)),
|
GameMode::Taiko => Self::Taiko(TaikoGradualDifficultyAttributes::new(map, mods)),
|
||||||
GameMode::CTB => Self::Catch(CatchGradualDifficultyAttributes::new(map, mods)),
|
GameMode::Catch => Self::Catch(CatchGradualDifficultyAttributes::new(map, mods)),
|
||||||
GameMode::MNA => Self::Mania(ManiaGradualDifficultyAttributes::new(map, mods)),
|
GameMode::Mania => Self::Mania(ManiaGradualDifficultyAttributes::new(map, mods)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,10 +285,10 @@ impl<'map> GradualPerformanceAttributes<'map> {
|
|||||||
/// Create a new gradual performance calculator for maps of any mode.
|
/// Create a new gradual performance calculator for maps of any mode.
|
||||||
pub fn new(map: &'map Beatmap, mods: u32) -> Self {
|
pub fn new(map: &'map Beatmap, mods: u32) -> Self {
|
||||||
match map.mode {
|
match map.mode {
|
||||||
GameMode::STD => Self::Osu(OsuGradualPerformanceAttributes::new(map, mods)),
|
GameMode::Osu => Self::Osu(OsuGradualPerformanceAttributes::new(map, mods)),
|
||||||
GameMode::TKO => Self::Taiko(TaikoGradualPerformanceAttributes::new(map, mods)),
|
GameMode::Taiko => Self::Taiko(TaikoGradualPerformanceAttributes::new(map, mods)),
|
||||||
GameMode::CTB => Self::Catch(CatchGradualPerformanceAttributes::new(map, mods)),
|
GameMode::Catch => Self::Catch(CatchGradualPerformanceAttributes::new(map, mods)),
|
||||||
GameMode::MNA => Self::Mania(ManiaGradualPerformanceAttributes::new(map, mods)),
|
GameMode::Mania => Self::Mania(ManiaGradualPerformanceAttributes::new(map, mods)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -80,7 +80,7 @@
|
|||||||
//! This could be done by using `passed_objects` as the amount of objects that were passed so far.
|
//! This could be done by using `passed_objects` as the amount of objects that were passed so far.
|
||||||
//! However, this requires to recalculate the beginning again and again, we can be more efficient than that.
|
//! However, this requires to recalculate the beginning again and again, we can be more efficient than that.
|
||||||
//!
|
//!
|
||||||
//! Instead, you should use `GradualDifficultyAttributes` and `GradualPerformanceAttributes`:
|
//! Instead, you should use [`GradualDifficultyAttributes`] and [`GradualPerformanceAttributes`]:
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use rosu_pp::{
|
//! use rosu_pp::{
|
||||||
@@ -255,24 +255,24 @@ impl BeatmapExt for Beatmap {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn stars(&self) -> AnyStars<'_> {
|
fn stars(&self) -> AnyStars<'_> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
GameMode::STD => AnyStars::Osu(OsuStars::new(self)),
|
GameMode::Osu => AnyStars::Osu(OsuStars::new(self)),
|
||||||
GameMode::MNA => AnyStars::Mania(ManiaStars::new(self)),
|
GameMode::Mania => AnyStars::Mania(ManiaStars::new(self)),
|
||||||
GameMode::TKO => AnyStars::Taiko(TaikoStars::new(self)),
|
GameMode::Taiko => AnyStars::Taiko(TaikoStars::new(self)),
|
||||||
GameMode::CTB => AnyStars::Catch(CatchStars::new(self)),
|
GameMode::Catch => AnyStars::Catch(CatchStars::new(self)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn max_pp(&self, mods: u32) -> PerformanceAttributes {
|
fn max_pp(&self, mods: u32) -> PerformanceAttributes {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
GameMode::STD => PerformanceAttributes::Osu(OsuPP::new(self).mods(mods).calculate()),
|
GameMode::Osu => PerformanceAttributes::Osu(OsuPP::new(self).mods(mods).calculate()),
|
||||||
GameMode::MNA => {
|
GameMode::Mania => {
|
||||||
PerformanceAttributes::Mania(ManiaPP::new(self).mods(mods).calculate())
|
PerformanceAttributes::Mania(ManiaPP::new(self).mods(mods).calculate())
|
||||||
}
|
}
|
||||||
GameMode::TKO => {
|
GameMode::Taiko => {
|
||||||
PerformanceAttributes::Taiko(TaikoPP::new(self).mods(mods).calculate())
|
PerformanceAttributes::Taiko(TaikoPP::new(self).mods(mods).calculate())
|
||||||
}
|
}
|
||||||
GameMode::CTB => {
|
GameMode::Catch => {
|
||||||
PerformanceAttributes::Catch(CatchPP::new(self).mods(mods).calculate())
|
PerformanceAttributes::Catch(CatchPP::new(self).mods(mods).calculate())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,10 +286,10 @@ impl BeatmapExt for Beatmap {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn strains(&self, mods: u32) -> Strains {
|
fn strains(&self, mods: u32) -> Strains {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
GameMode::STD => Strains::Osu(OsuStars::new(self).mods(mods).strains()),
|
GameMode::Osu => Strains::Osu(OsuStars::new(self).mods(mods).strains()),
|
||||||
GameMode::MNA => Strains::Mania(ManiaStars::new(self).mods(mods).strains()),
|
GameMode::Mania => Strains::Mania(ManiaStars::new(self).mods(mods).strains()),
|
||||||
GameMode::TKO => Strains::Taiko(TaikoStars::new(self).mods(mods).strains()),
|
GameMode::Taiko => Strains::Taiko(TaikoStars::new(self).mods(mods).strains()),
|
||||||
GameMode::CTB => Strains::Catch(CatchStars::new(self).mods(mods).strains()),
|
GameMode::Catch => Strains::Catch(CatchStars::new(self).mods(mods).strains()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+218
-218
@@ -1,218 +1,218 @@
|
|||||||
use std::{
|
use std::{
|
||||||
iter::{self, Skip, Zip},
|
iter::{self, Skip, Zip},
|
||||||
slice::Iter,
|
slice::Iter,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mania::{strain::Strain, SECTION_LEN},
|
mania::{strain::Strain, SECTION_LEN},
|
||||||
parse::HitObject,
|
parse::HitObject,
|
||||||
Beatmap, GameMode, Mods,
|
Beatmap, GameMode, Mods,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{DifficultyHitObject, ManiaDifficultyAttributes, STAR_SCALING_FACTOR};
|
use super::{DifficultyHitObject, ManiaDifficultyAttributes, STAR_SCALING_FACTOR};
|
||||||
|
|
||||||
/// Gradually calculate the difficulty attributes of an osu!mania map.
|
/// Gradually calculate the difficulty attributes of an osu!mania map.
|
||||||
///
|
///
|
||||||
/// Note that this struct implements [`Iterator`](std::iter::Iterator).
|
/// Note that this struct implements [`Iterator`](std::iter::Iterator).
|
||||||
/// On every call of [`Iterator::next`](std::iter::Iterator::next), the map's next hit object will
|
/// On every call of [`Iterator::next`](std::iter::Iterator::next), the map's next hit object will
|
||||||
/// be processed and the [`ManiaDifficultyAttributes`] will be updated and returned.
|
/// be processed and the [`ManiaDifficultyAttributes`] will be updated and returned.
|
||||||
///
|
///
|
||||||
/// If you want to calculate performance attributes, use
|
/// If you want to calculate performance attributes, use
|
||||||
/// [`ManiaGradualPerformanceAttributes`](crate::mania::ManiaGradualPerformanceAttributes) instead.
|
/// [`ManiaGradualPerformanceAttributes`](crate::mania::ManiaGradualPerformanceAttributes) instead.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rosu_pp::{Beatmap, mania::ManiaGradualDifficultyAttributes};
|
/// use rosu_pp::{Beatmap, mania::ManiaGradualDifficultyAttributes};
|
||||||
///
|
///
|
||||||
/// # /*
|
/// # /*
|
||||||
/// let map: Beatmap = ...
|
/// let map: Beatmap = ...
|
||||||
/// # */
|
/// # */
|
||||||
/// # let map = Beatmap::default();
|
/// # let map = Beatmap::default();
|
||||||
///
|
///
|
||||||
/// let mods = 64; // DT
|
/// let mods = 64; // DT
|
||||||
/// let mut iter = ManiaGradualDifficultyAttributes::new(&map, mods);
|
/// let mut iter = ManiaGradualDifficultyAttributes::new(&map, mods);
|
||||||
///
|
///
|
||||||
/// let attrs1 = iter.next(); // the difficulty of the map after the first hit object
|
/// let attrs1 = iter.next(); // the difficulty of the map after the first hit object
|
||||||
/// let attrs2 = iter.next(); // after the second hit object
|
/// let attrs2 = iter.next(); // after the second hit object
|
||||||
///
|
///
|
||||||
/// // Remaining hit objects
|
/// // Remaining hit objects
|
||||||
/// for difficulty in iter {
|
/// for difficulty in iter {
|
||||||
/// // ...
|
/// // ...
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ManiaGradualDifficultyAttributes<'map> {
|
pub struct ManiaGradualDifficultyAttributes<'map> {
|
||||||
pub(crate) idx: usize,
|
pub(crate) idx: usize,
|
||||||
difficulty_objects: ManiaObjectIter<'map>,
|
difficulty_objects: ManiaObjectIter<'map>,
|
||||||
strain: Strain,
|
strain: Strain,
|
||||||
curr_section_end: f64,
|
curr_section_end: f64,
|
||||||
strain_peak_buf: Vec<f64>,
|
strain_peak_buf: Vec<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'map> ManiaGradualDifficultyAttributes<'map> {
|
impl<'map> ManiaGradualDifficultyAttributes<'map> {
|
||||||
/// Create a new difficulty attributes iterator for osu!mania maps.
|
/// Create a new difficulty attributes iterator for osu!mania maps.
|
||||||
pub fn new(map: &'map Beatmap, mods: impl Mods) -> Self {
|
pub fn new(map: &'map Beatmap, mods: impl Mods) -> Self {
|
||||||
let rounded_cs = map.cs.round();
|
let rounded_cs = map.cs.round();
|
||||||
|
|
||||||
let columns = match map.mode {
|
let columns = match map.mode {
|
||||||
GameMode::MNA => rounded_cs.max(1.0) as u8,
|
GameMode::Mania => rounded_cs.max(1.0) as u8,
|
||||||
GameMode::STD => {
|
GameMode::Osu => {
|
||||||
let rounded_od = map.od.round();
|
let rounded_od = map.od.round();
|
||||||
|
|
||||||
let n_objects = map.n_circles + map.n_sliders + map.n_spinners;
|
let n_objects = map.n_circles + map.n_sliders + map.n_spinners;
|
||||||
let slider_or_spinner_ratio = (n_objects - map.n_circles) as f32 / n_objects as f32;
|
let slider_or_spinner_ratio = (n_objects - map.n_circles) as f32 / n_objects as f32;
|
||||||
|
|
||||||
if slider_or_spinner_ratio < 0.2 {
|
if slider_or_spinner_ratio < 0.2 {
|
||||||
7
|
7
|
||||||
} else if slider_or_spinner_ratio < 0.3 || rounded_cs >= 5.0 {
|
} else if slider_or_spinner_ratio < 0.3 || rounded_cs >= 5.0 {
|
||||||
6 + (rounded_od > 5.0) as u8
|
6 + (rounded_od > 5.0) as u8
|
||||||
} else if slider_or_spinner_ratio > 0.6 {
|
} else if slider_or_spinner_ratio > 0.6 {
|
||||||
4 + (rounded_od > 4.0) as u8
|
4 + (rounded_od > 4.0) as u8
|
||||||
} else {
|
} else {
|
||||||
(rounded_od as u8 + 1).max(4).min(7)
|
(rounded_od as u8 + 1).max(4).min(7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => panic!("can not calculate mania difficulty on a {:?} map", other),
|
other => panic!("can not calculate mania difficulty on a {:?} map", other),
|
||||||
};
|
};
|
||||||
|
|
||||||
let clock_rate = mods.clock_rate();
|
let clock_rate = mods.clock_rate();
|
||||||
let strain = Strain::new(columns);
|
let strain = Strain::new(columns);
|
||||||
let columns = columns as f32;
|
let columns = columns as f32;
|
||||||
let difficulty_objects = ManiaObjectIter::new(&map.hit_objects, columns, clock_rate);
|
let difficulty_objects = ManiaObjectIter::new(&map.hit_objects, columns, clock_rate);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
idx: 0,
|
idx: 0,
|
||||||
difficulty_objects,
|
difficulty_objects,
|
||||||
strain,
|
strain,
|
||||||
curr_section_end: 0.0,
|
curr_section_end: 0.0,
|
||||||
strain_peak_buf: Vec::new(),
|
strain_peak_buf: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for ManiaGradualDifficultyAttributes<'_> {
|
impl Iterator for ManiaGradualDifficultyAttributes<'_> {
|
||||||
type Item = ManiaDifficultyAttributes;
|
type Item = ManiaDifficultyAttributes;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.idx = self.idx.saturating_add(1);
|
self.idx = self.idx.saturating_add(1);
|
||||||
|
|
||||||
if self.idx == 1 {
|
if self.idx == 1 {
|
||||||
return (!self.difficulty_objects.is_empty).then(ManiaDifficultyAttributes::default);
|
return (!self.difficulty_objects.is_empty).then(ManiaDifficultyAttributes::default);
|
||||||
}
|
}
|
||||||
|
|
||||||
let h = self.difficulty_objects.next()?;
|
let h = self.difficulty_objects.next()?;
|
||||||
|
|
||||||
if self.idx == 2 {
|
if self.idx == 2 {
|
||||||
self.curr_section_end = (h.start_time / SECTION_LEN).ceil() * SECTION_LEN;
|
self.curr_section_end = (h.start_time / SECTION_LEN).ceil() * SECTION_LEN;
|
||||||
} else {
|
} else {
|
||||||
while h.start_time > self.curr_section_end {
|
while h.start_time > self.curr_section_end {
|
||||||
self.strain.save_current_peak();
|
self.strain.save_current_peak();
|
||||||
self.strain.start_new_section_from(self.curr_section_end);
|
self.strain.start_new_section_from(self.curr_section_end);
|
||||||
self.curr_section_end += SECTION_LEN;
|
self.curr_section_end += SECTION_LEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.strain.process(&h);
|
self.strain.process(&h);
|
||||||
|
|
||||||
let missing = self.strain.strain_peaks.len() + 1 - self.strain_peak_buf.len();
|
let missing = self.strain.strain_peaks.len() + 1 - self.strain_peak_buf.len();
|
||||||
self.strain_peak_buf.extend(iter::repeat(0.0).take(missing));
|
self.strain_peak_buf.extend(iter::repeat(0.0).take(missing));
|
||||||
|
|
||||||
self.strain_peak_buf[..self.strain.strain_peaks.len()]
|
self.strain_peak_buf[..self.strain.strain_peaks.len()]
|
||||||
.copy_from_slice(&self.strain.strain_peaks);
|
.copy_from_slice(&self.strain.strain_peaks);
|
||||||
|
|
||||||
if let Some(last) = self.strain_peak_buf.last_mut() {
|
if let Some(last) = self.strain_peak_buf.last_mut() {
|
||||||
*last = self.strain.curr_section_peak;
|
*last = self.strain.curr_section_peak;
|
||||||
}
|
}
|
||||||
|
|
||||||
let stars = Strain::difficulty_value(&mut self.strain_peak_buf) * STAR_SCALING_FACTOR;
|
let stars = Strain::difficulty_value(&mut self.strain_peak_buf) * STAR_SCALING_FACTOR;
|
||||||
|
|
||||||
Some(ManiaDifficultyAttributes { stars })
|
Some(ManiaDifficultyAttributes { stars })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
|
|
||||||
(len, Some(len))
|
(len, Some(len))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExactSizeIterator for ManiaGradualDifficultyAttributes<'_> {
|
impl ExactSizeIterator for ManiaGradualDifficultyAttributes<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.difficulty_objects.len() + (self.idx == 0) as usize
|
self.difficulty_objects.len() + (self.idx == 0) as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct ManiaObjectIter<'map> {
|
struct ManiaObjectIter<'map> {
|
||||||
hit_objects: Zip<Skip<Iter<'map, HitObject>>, Iter<'map, HitObject>>,
|
hit_objects: Zip<Skip<Iter<'map, HitObject>>, Iter<'map, HitObject>>,
|
||||||
columns: f32,
|
columns: f32,
|
||||||
clock_rate: f64,
|
clock_rate: f64,
|
||||||
is_empty: bool,
|
is_empty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'map> ManiaObjectIter<'map> {
|
impl<'map> ManiaObjectIter<'map> {
|
||||||
fn new(hit_objects: &'map [HitObject], columns: f32, clock_rate: f64) -> Self {
|
fn new(hit_objects: &'map [HitObject], columns: f32, clock_rate: f64) -> Self {
|
||||||
let is_empty = hit_objects.is_empty();
|
let is_empty = hit_objects.is_empty();
|
||||||
let hit_objects = hit_objects.iter().skip(1).zip(hit_objects);
|
let hit_objects = hit_objects.iter().skip(1).zip(hit_objects);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
hit_objects,
|
hit_objects,
|
||||||
columns,
|
columns,
|
||||||
clock_rate,
|
clock_rate,
|
||||||
is_empty,
|
is_empty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'map> Iterator for ManiaObjectIter<'map> {
|
impl<'map> Iterator for ManiaObjectIter<'map> {
|
||||||
type Item = DifficultyHitObject<'map>;
|
type Item = DifficultyHitObject<'map>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let (base, prev) = self.hit_objects.next()?;
|
let (base, prev) = self.hit_objects.next()?;
|
||||||
let obj = DifficultyHitObject::new(base, prev, self.columns, self.clock_rate);
|
let obj = DifficultyHitObject::new(base, prev, self.columns, self.clock_rate);
|
||||||
|
|
||||||
Some(obj)
|
Some(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
self.hit_objects.size_hint()
|
self.hit_objects.size_hint()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExactSizeIterator for ManiaObjectIter<'_> {
|
impl ExactSizeIterator for ManiaObjectIter<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.hit_objects.len()
|
self.hit_objects.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_map() {
|
fn empty_map() {
|
||||||
let map = Beatmap::default();
|
let map = Beatmap::default();
|
||||||
let mut attributes = ManiaGradualDifficultyAttributes::new(&map, 0);
|
let mut attributes = ManiaGradualDifficultyAttributes::new(&map, 0);
|
||||||
assert!(attributes.next().is_none());
|
assert!(attributes.next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "async_tokio", feature = "async_std")))]
|
#[cfg(not(any(feature = "async_tokio", feature = "async_std")))]
|
||||||
#[test]
|
#[test]
|
||||||
fn iter_end_eq_regular() {
|
fn iter_end_eq_regular() {
|
||||||
let map = Beatmap::from_path("./maps/1974394.osu").expect("failed to parse map");
|
let map = Beatmap::from_path("./maps/1974394.osu").expect("failed to parse map");
|
||||||
let mods = 64;
|
let mods = 64;
|
||||||
let regular = crate::ManiaStars::new(&map).mods(mods).calculate();
|
let regular = crate::ManiaStars::new(&map).mods(mods).calculate();
|
||||||
|
|
||||||
let iter_end = ManiaGradualDifficultyAttributes::new(&map, mods)
|
let iter_end = ManiaGradualDifficultyAttributes::new(&map, mods)
|
||||||
.last()
|
.last()
|
||||||
.expect("empty iter");
|
.expect("empty iter");
|
||||||
|
|
||||||
assert_eq!(regular, iter_end);
|
assert_eq!(regular, iter_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -140,8 +140,8 @@ fn calculate_strain(params: ManiaStars<'_>) -> Strain {
|
|||||||
let rounded_cs = map.cs.round();
|
let rounded_cs = map.cs.round();
|
||||||
|
|
||||||
let columns = match map.mode {
|
let columns = match map.mode {
|
||||||
GameMode::MNA => rounded_cs.max(1.0) as u8,
|
GameMode::Mania => rounded_cs.max(1.0) as u8,
|
||||||
GameMode::STD => {
|
GameMode::Osu => {
|
||||||
let rounded_od = map.od.round();
|
let rounded_od = map.od.round();
|
||||||
|
|
||||||
let n_objects = map.n_circles + map.n_sliders + map.n_spinners;
|
let n_objects = map.n_circles + map.n_sliders + map.n_spinners;
|
||||||
@@ -270,7 +270,7 @@ impl<'map> From<OsuStars<'map>> for ManiaStars<'map> {
|
|||||||
} = osu;
|
} = osu;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
map: map.convert_mode(GameMode::MNA),
|
map: map.convert_mode(GameMode::Mania),
|
||||||
mods,
|
mods,
|
||||||
passed_objects,
|
passed_objects,
|
||||||
clock_rate,
|
clock_rate,
|
||||||
|
|||||||
+1
-1
@@ -225,7 +225,7 @@ impl<'map> From<OsuPP<'map>> for ManiaPP<'map> {
|
|||||||
} = osu;
|
} = osu;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
map: map.convert_mode(GameMode::MNA),
|
map: map.convert_mode(GameMode::Mania),
|
||||||
stars: None,
|
stars: None,
|
||||||
mods,
|
mods,
|
||||||
score: None,
|
score: None,
|
||||||
|
|||||||
+4
-4
@@ -71,10 +71,10 @@ impl<'map> OsuStars<'map> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn mode(self, mode: GameMode) -> AnyStars<'map> {
|
pub fn mode(self, mode: GameMode) -> AnyStars<'map> {
|
||||||
match mode {
|
match mode {
|
||||||
GameMode::STD => AnyStars::Osu(self),
|
GameMode::Osu => AnyStars::Osu(self),
|
||||||
GameMode::TKO => AnyStars::Taiko(self.into()),
|
GameMode::Taiko => AnyStars::Taiko(self.into()),
|
||||||
GameMode::CTB => AnyStars::Catch(self.into()),
|
GameMode::Catch => AnyStars::Catch(self.into()),
|
||||||
GameMode::MNA => AnyStars::Mania(self.into()),
|
GameMode::Mania => AnyStars::Mania(self.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -73,10 +73,10 @@ impl<'map> OsuPP<'map> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn mode(self, mode: GameMode) -> AnyPP<'map> {
|
pub fn mode(self, mode: GameMode) -> AnyPP<'map> {
|
||||||
match mode {
|
match mode {
|
||||||
GameMode::STD => AnyPP::Osu(self),
|
GameMode::Osu => AnyPP::Osu(self),
|
||||||
GameMode::TKO => AnyPP::Taiko(self.into()),
|
GameMode::Taiko => AnyPP::Taiko(self.into()),
|
||||||
GameMode::CTB => AnyPP::Catch(self.into()),
|
GameMode::Catch => AnyPP::Catch(self.into()),
|
||||||
GameMode::MNA => AnyPP::Mania(self.into()),
|
GameMode::Mania => AnyPP::Mania(self.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -101,10 +101,10 @@ macro_rules! parse_general_body {
|
|||||||
|
|
||||||
if key == b"Mode" {
|
if key == b"Mode" {
|
||||||
mode = match value {
|
mode = match value {
|
||||||
"0" => Some(GameMode::STD),
|
"0" => Some(GameMode::Osu),
|
||||||
"1" => Some(GameMode::TKO),
|
"1" => Some(GameMode::Taiko),
|
||||||
"2" => Some(GameMode::CTB),
|
"2" => Some(GameMode::Catch),
|
||||||
"3" => Some(GameMode::MNA),
|
"3" => Some(GameMode::Mania),
|
||||||
_ => return Err(ParseError::InvalidMode),
|
_ => return Err(ParseError::InvalidMode),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ macro_rules! parse_general_body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$self.mode = mode.unwrap_or(GameMode::STD);
|
$self.mode = mode.unwrap_or(GameMode::Osu);
|
||||||
$self.stack_leniency = stack_leniency.unwrap_or(0.7);
|
$self.stack_leniency = stack_leniency.unwrap_or(0.7);
|
||||||
|
|
||||||
Ok(empty)
|
Ok(empty)
|
||||||
@@ -456,7 +456,7 @@ macro_rules! parse_hitobjects_body {
|
|||||||
|
|
||||||
// BUG: If [General] section comes after [HitObjects] then the mode
|
// BUG: If [General] section comes after [HitObjects] then the mode
|
||||||
// won't be set yet so mania objects won't be sorted properly
|
// won't be set yet so mania objects won't be sorted properly
|
||||||
if $self.mode == GameMode::MNA {
|
if $self.mode == GameMode::Mania {
|
||||||
// First a _stable_ sort by time
|
// First a _stable_ sort by time
|
||||||
$self
|
$self
|
||||||
.hit_objects
|
.hit_objects
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ impl<'map> AnyPP<'map> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(map: &'map Beatmap) -> Self {
|
pub fn new(map: &'map Beatmap) -> Self {
|
||||||
match map.mode {
|
match map.mode {
|
||||||
GameMode::CTB => Self::Catch(CatchPP::new(map)),
|
GameMode::Catch => Self::Catch(CatchPP::new(map)),
|
||||||
GameMode::MNA => Self::Mania(ManiaPP::new(map)),
|
GameMode::Mania => Self::Mania(ManiaPP::new(map)),
|
||||||
GameMode::STD => Self::Osu(OsuPP::new(map)),
|
GameMode::Osu => Self::Osu(OsuPP::new(map)),
|
||||||
GameMode::TKO => Self::Taiko(TaikoPP::new(map)),
|
GameMode::Taiko => Self::Taiko(TaikoPP::new(map)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,10 +90,10 @@ impl<'map> AnyPP<'map> {
|
|||||||
pub fn mode(self, mode: GameMode) -> Self {
|
pub fn mode(self, mode: GameMode) -> Self {
|
||||||
match self {
|
match self {
|
||||||
AnyPP::Osu(o) => match mode {
|
AnyPP::Osu(o) => match mode {
|
||||||
GameMode::STD => AnyPP::Osu(o),
|
GameMode::Osu => AnyPP::Osu(o),
|
||||||
GameMode::TKO => AnyPP::Taiko(o.into()),
|
GameMode::Taiko => AnyPP::Taiko(o.into()),
|
||||||
GameMode::CTB => AnyPP::Catch(o.into()),
|
GameMode::Catch => AnyPP::Catch(o.into()),
|
||||||
GameMode::MNA => AnyPP::Mania(o.into()),
|
GameMode::Mania => AnyPP::Mania(o.into()),
|
||||||
},
|
},
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -37,10 +37,10 @@ impl<'map> AnyStars<'map> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(map: &'map Beatmap) -> Self {
|
pub fn new(map: &'map Beatmap) -> Self {
|
||||||
match map.mode {
|
match map.mode {
|
||||||
GameMode::CTB => Self::Catch(CatchStars::new(map)),
|
GameMode::Catch => Self::Catch(CatchStars::new(map)),
|
||||||
GameMode::MNA => Self::Mania(ManiaStars::new(map)),
|
GameMode::Mania => Self::Mania(ManiaStars::new(map)),
|
||||||
GameMode::STD => Self::Osu(OsuStars::new(map)),
|
GameMode::Osu => Self::Osu(OsuStars::new(map)),
|
||||||
GameMode::TKO => Self::Taiko(TaikoStars::new(map)),
|
GameMode::Taiko => Self::Taiko(TaikoStars::new(map)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,10 +49,10 @@ impl<'map> AnyStars<'map> {
|
|||||||
pub fn mode(self, mode: GameMode) -> Self {
|
pub fn mode(self, mode: GameMode) -> Self {
|
||||||
match self {
|
match self {
|
||||||
AnyStars::Osu(o) => match mode {
|
AnyStars::Osu(o) => match mode {
|
||||||
GameMode::STD => AnyStars::Osu(o),
|
GameMode::Osu => AnyStars::Osu(o),
|
||||||
GameMode::TKO => AnyStars::Taiko(o.into()),
|
GameMode::Taiko => AnyStars::Taiko(o.into()),
|
||||||
GameMode::CTB => AnyStars::Catch(o.into()),
|
GameMode::Catch => AnyStars::Catch(o.into()),
|
||||||
GameMode::MNA => AnyStars::Mania(o.into()),
|
GameMode::Mania => AnyStars::Mania(o.into()),
|
||||||
},
|
},
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -362,7 +362,7 @@ impl<'map> From<OsuStars<'map>> for TaikoStars<'map> {
|
|||||||
} = osu;
|
} = osu;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
map: map.convert_mode(GameMode::TKO),
|
map: map.convert_mode(GameMode::Taiko),
|
||||||
mods,
|
mods,
|
||||||
passed_objects,
|
passed_objects,
|
||||||
clock_rate,
|
clock_rate,
|
||||||
|
|||||||
+1
-1
@@ -321,7 +321,7 @@ impl<'map> From<OsuPP<'map>> for TaikoPP<'map> {
|
|||||||
} = osu;
|
} = osu;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
map: map.convert_mode(GameMode::TKO),
|
map: map.convert_mode(GameMode::Taiko),
|
||||||
attributes: None,
|
attributes: None,
|
||||||
mods,
|
mods,
|
||||||
combo,
|
combo,
|
||||||
|
|||||||
Reference in New Issue
Block a user