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.
|
- [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
|
- Fixed out of bounds panic on maps with single-control-point linear sliders
|
||||||
- [BREAKING] Added the field `TaikoDifficultyAttributes::max_combo`
|
- [BREAKING] Added the field `TaikoDifficultyAttributes::max_combo`
|
||||||
|
- Added method `Beatmap::bpm`
|
||||||
|
- Added method `DifficultyAttributes::max_combo`
|
||||||
|
|
||||||
# v0.3.0
|
# v0.3.0
|
||||||
|
|
||||||
|
|||||||
+32
-1
@@ -318,6 +318,37 @@ impl DifficultyAttributes {
|
|||||||
Self::Taiko(attributes) => attributes.stars,
|
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")]
|
#[cfg(feature = "fruits")]
|
||||||
@@ -407,7 +438,7 @@ impl PerformanceAttributes {
|
|||||||
#[cfg(feature = "osu")]
|
#[cfg(feature = "osu")]
|
||||||
Self::Osu(attributes) => DifficultyAttributes::Osu(attributes.attributes.clone()),
|
Self::Osu(attributes) => DifficultyAttributes::Osu(attributes.attributes.clone()),
|
||||||
#[cfg(feature = "taiko")]
|
#[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) => {{
|
($buf:ident) => {{
|
||||||
let mut line = $buf.trim_end();
|
let mut line = $buf.trim_end();
|
||||||
|
|
||||||
if line.is_empty()
|
if skip_line(line) {
|
||||||
|| line.starts_with("//")
|
|
||||||
|| line.starts_with(' ')
|
|
||||||
|| line.starts_with('_')
|
|
||||||
{
|
|
||||||
$buf.clear();
|
$buf.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -284,6 +280,42 @@ macro_rules! parse_timingpoints_body {
|
|||||||
(short => $self:ident, $reader:ident, $buf:ident, $section:ident) => {{
|
(short => $self:ident, $reader:ident, $buf:ident, $section:ident) => {{
|
||||||
let mut empty = true;
|
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 {
|
while read_line!($reader, $buf)? != 0 {
|
||||||
let line = line_prepare!($buf);
|
let line = line_prepare!($buf);
|
||||||
|
|
||||||
@@ -782,6 +814,9 @@ pub struct Beatmap {
|
|||||||
/// All hitobjects of the beatmap.
|
/// All hitobjects of the beatmap.
|
||||||
pub hit_objects: Vec<HitObject>,
|
pub hit_objects: Vec<HitObject>,
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "osu", feature = "fruits")))]
|
||||||
|
bpm: f64,
|
||||||
|
|
||||||
#[cfg(any(feature = "osu", feature = "fruits"))]
|
#[cfg(any(feature = "osu", feature = "fruits"))]
|
||||||
/// Timing points that indicate a new timing section.
|
/// Timing points that indicate a new timing section.
|
||||||
pub timing_points: Vec<TimingPoint>,
|
pub timing_points: Vec<TimingPoint>,
|
||||||
@@ -811,6 +846,23 @@ impl Beatmap {
|
|||||||
pub fn attributes(&self) -> BeatmapAttributes {
|
pub fn attributes(&self) -> BeatmapAttributes {
|
||||||
BeatmapAttributes::new(self.ar, self.od, self.cs, self.hp)
|
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")]
|
#[cfg(feature = "sliders")]
|
||||||
@@ -996,6 +1048,14 @@ impl Beatmap {
|
|||||||
from_path!(async Path);
|
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]
|
#[inline]
|
||||||
fn split_colon(line: &str) -> Option<(&str, &str)> {
|
fn split_colon(line: &str) -> Option<(&str, &str)> {
|
||||||
let mut split = line.split(':');
|
let mut split = line.split(':');
|
||||||
|
|||||||
Reference in New Issue
Block a user