added Beatmap::bpm and DifficultyAttributes::max_combo methods
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
- [BREAKING] Removed the `last_control_point` field of `HitObjectKind::Slider` when neither the `osu` nor the `fruits` feature is enabled.
|
||||
- Fixed out of bounds panic on maps with single-control-point linear sliders
|
||||
- [BREAKING] Added the field `TaikoDifficultyAttributes::max_combo`
|
||||
- Added method `Beatmap::bpm`
|
||||
- Added method `DifficultyAttributes::max_combo`
|
||||
|
||||
# v0.3.0
|
||||
|
||||
|
||||
+32
-1
@@ -318,6 +318,37 @@ impl DifficultyAttributes {
|
||||
Self::Taiko(attributes) => attributes.stars,
|
||||
}
|
||||
}
|
||||
|
||||
/// The max combo of the map.
|
||||
///
|
||||
/// This will only be `None` for attributes of osu!mania maps.
|
||||
#[inline]
|
||||
#[cfg(feature = "mania")]
|
||||
pub fn max_combo(&self) -> Option<usize> {
|
||||
match self {
|
||||
#[cfg(feature = "fruits")]
|
||||
Self::Fruits(attributes) => Some(attributes.max_combo),
|
||||
Self::Mania(_) => None,
|
||||
#[cfg(feature = "osu")]
|
||||
Self::Osu(attributes) => Some(attributes.max_combo),
|
||||
#[cfg(feature = "taiko")]
|
||||
Self::Taiko(attributes) => Some(attributes.max_combo),
|
||||
}
|
||||
}
|
||||
|
||||
/// The max combo of the map.
|
||||
#[inline]
|
||||
#[cfg(not(feature = "mania"))]
|
||||
pub fn max_combo(&self) -> usize {
|
||||
match self {
|
||||
#[cfg(feature = "fruits")]
|
||||
Self::Fruits(attributes) => attributes.max_combo,
|
||||
#[cfg(feature = "osu")]
|
||||
Self::Osu(attributes) => attributes.max_combo,
|
||||
#[cfg(feature = "taiko")]
|
||||
Self::Taiko(attributes) => attributes.max_combo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fruits")]
|
||||
@@ -407,7 +438,7 @@ impl PerformanceAttributes {
|
||||
#[cfg(feature = "osu")]
|
||||
Self::Osu(attributes) => DifficultyAttributes::Osu(attributes.attributes.clone()),
|
||||
#[cfg(feature = "taiko")]
|
||||
Self::Taiko(attributes) => DifficultyAttributes::Taiko(attributes.attributes.clone()),
|
||||
Self::Taiko(attributes) => DifficultyAttributes::Taiko(attributes.attributes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+65
-5
@@ -71,11 +71,7 @@ macro_rules! line_prepare {
|
||||
($buf:ident) => {{
|
||||
let mut line = $buf.trim_end();
|
||||
|
||||
if line.is_empty()
|
||||
|| line.starts_with("//")
|
||||
|| line.starts_with(' ')
|
||||
|| line.starts_with('_')
|
||||
{
|
||||
if skip_line(line) {
|
||||
$buf.clear();
|
||||
continue;
|
||||
}
|
||||
@@ -284,6 +280,42 @@ macro_rules! parse_timingpoints_body {
|
||||
(short => $self:ident, $reader:ident, $buf:ident, $section:ident) => {{
|
||||
let mut empty = true;
|
||||
|
||||
// Only parse the first timing point to calculate the bpm
|
||||
if read_line!($reader, $buf)? != 0 {
|
||||
let line = {
|
||||
let mut line = $buf.trim_end();
|
||||
|
||||
if skip_line(line) {
|
||||
$buf.clear();
|
||||
return Ok(empty);
|
||||
}
|
||||
|
||||
if let Some(idx) = line.find("//") {
|
||||
line = &line[..idx];
|
||||
}
|
||||
|
||||
line
|
||||
};
|
||||
|
||||
if line.starts_with('[') && line.ends_with(']') {
|
||||
*$section = Section::from_str(&line[1..line.len() - 1]);
|
||||
empty = false;
|
||||
$buf.clear();
|
||||
return Ok(empty);
|
||||
}
|
||||
|
||||
let beat_len = line
|
||||
.split(',')
|
||||
.nth(1)
|
||||
.next_field("beat_len")?
|
||||
.trim()
|
||||
.parse()?;
|
||||
|
||||
$self.bpm = bpm(beat_len);
|
||||
|
||||
$buf.clear();
|
||||
}
|
||||
|
||||
while read_line!($reader, $buf)? != 0 {
|
||||
let line = line_prepare!($buf);
|
||||
|
||||
@@ -782,6 +814,9 @@ pub struct Beatmap {
|
||||
/// All hitobjects of the beatmap.
|
||||
pub hit_objects: Vec<HitObject>,
|
||||
|
||||
#[cfg(not(any(feature = "osu", feature = "fruits")))]
|
||||
bpm: f64,
|
||||
|
||||
#[cfg(any(feature = "osu", feature = "fruits"))]
|
||||
/// Timing points that indicate a new timing section.
|
||||
pub timing_points: Vec<TimingPoint>,
|
||||
@@ -811,6 +846,23 @@ impl Beatmap {
|
||||
pub fn attributes(&self) -> BeatmapAttributes {
|
||||
BeatmapAttributes::new(self.ar, self.od, self.cs, self.hp)
|
||||
}
|
||||
|
||||
/// The beats per minute of the map.
|
||||
#[cfg(any(feature = "osu", feature = "fruits"))]
|
||||
#[inline]
|
||||
pub fn bpm(&self) -> f64 {
|
||||
match self.timing_points.first() {
|
||||
Some(point) => bpm(point.beat_len),
|
||||
None => 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// The beats per minute of the map.
|
||||
#[cfg(not(any(feature = "osu", feature = "fruits")))]
|
||||
#[inline]
|
||||
pub fn bpm(&self) -> f64 {
|
||||
self.bpm
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sliders")]
|
||||
@@ -996,6 +1048,14 @@ impl Beatmap {
|
||||
from_path!(async Path);
|
||||
}
|
||||
|
||||
fn bpm(beat_len: f64) -> f64 {
|
||||
beat_len.recip() * 1000.0 * 60.0
|
||||
}
|
||||
|
||||
fn skip_line(line: &str) -> bool {
|
||||
line.is_empty() || line.starts_with("//") || line.starts_with(' ') || line.starts_with('_')
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn split_colon(line: &str) -> Option<(&str, &str)> {
|
||||
let mut split = line.split(':');
|
||||
|
||||
Reference in New Issue
Block a user