parse: handle many curvepoints efficiently

This commit is contained in:
MaxOhn
2021-02-04 16:27:07 +01:00
parent f429509c75
commit 09e88c2872
3 changed files with 32 additions and 6 deletions
+3
View File
@@ -1,5 +1,8 @@
# Upcoming # Upcoming
- parse:
- Efficiently handle huge amounts of curvepoints
- osu: - osu:
- Fixed panic on unwrapping unavailable hit results - Fixed panic on unwrapping unavailable hit results
- Fixed occasional underflow when calculating pp with passed_objects - Fixed occasional underflow when calculating pp with passed_objects
+6 -6
View File
@@ -280,7 +280,7 @@ mod tests {
#[test] #[test]
#[ignore] #[ignore]
fn no_leniency_single() { fn no_leniency_single() {
let file = match File::open("./maps/1791963.osu") { let file = match File::open("./maps/2573164.osu") {
Ok(file) => file, Ok(file) => file,
Err(why) => panic!("Could not open file: {}", why), Err(why) => panic!("Could not open file: {}", why),
}; };
@@ -291,11 +291,11 @@ mod tests {
}; };
let result = OsuPP::new(&map) let result = OsuPP::new(&map)
.n300(1206) .mods(0)
.n100(15) // .n300(1206)
.n50(0) // .n100(15)
.combo(1643) // .n50(0)
.mods(24) // .combo(1643)
.calculate(); .calculate();
println!("Stars: {}", result.stars()); println!("Stars: {}", result.stars());
+23
View File
@@ -115,6 +115,12 @@ pub struct Beatmap {
pub(crate) const OSU_FILE_HEADER: &str = "osu file format v"; pub(crate) const OSU_FILE_HEADER: &str = "osu file format v";
#[cfg(any(
feature = "fruits",
all(feature = "osu", not(feature = "no_sliders_no_leniency"))
))]
const CURVE_POINT_THRESHOLD: usize = 256;
impl Beatmap { impl Beatmap {
const CIRCLE_FLAG: u8 = 1 << 0; const CIRCLE_FLAG: u8 = 1 << 0;
const SLIDER_FLAG: u8 = 1 << 1; const SLIDER_FLAG: u8 = 1 << 1;
@@ -476,6 +482,23 @@ impl Beatmap {
} }
} }
// Reduce amount of curvepoints but keep the elements evenly spaced.
// Necessary to handle maps like XNOR (2573164) that have
// tens of thousands of curvepoints more efficiently.
if curve_points.len() > CURVE_POINT_THRESHOLD {
while curve_points.len() > CURVE_POINT_THRESHOLD {
let last = curve_points[curve_points.len() - 1];
let last_idx = (curve_points.len() - 1) / 2;
for i in 1..=last_idx {
curve_points.swap(i, 2 * i);
}
curve_points[last_idx] = last;
curve_points.truncate(last_idx + 1);
}
}
if curve_points.is_empty() { if curve_points.is_empty() {
HitObjectKind::Circle HitObjectKind::Circle
} else { } else {