osu: finished all_included version
This commit is contained in:
@@ -24,9 +24,9 @@ impl<'h> DifficultyObject<'h> {
|
||||
let delta = (base.time - prev.time) / clock_rate;
|
||||
let strain_time = delta.max(50.0);
|
||||
|
||||
let pos = base.pos;
|
||||
let pos = base.pos; // stacked position
|
||||
let travel_dist = prev.travel_dist();
|
||||
let prev_cursor_pos = prev.end_pos();
|
||||
let prev_cursor_pos = prev.lazy_end_pos();
|
||||
|
||||
let jump_dist = if base.is_spinner() {
|
||||
0.0
|
||||
@@ -35,9 +35,9 @@ impl<'h> DifficultyObject<'h> {
|
||||
};
|
||||
|
||||
let angle = prev_prev.map(|prev_prev| {
|
||||
let prev_prev_cursor_pos = prev_prev.end_pos();
|
||||
let prev_prev_cursor_pos = prev_prev.lazy_end_pos();
|
||||
|
||||
let v1 = prev_prev_cursor_pos - prev_cursor_pos;
|
||||
let v1 = prev_prev_cursor_pos - prev.pos;
|
||||
let v2 = pos - prev_cursor_pos;
|
||||
|
||||
let dot = v1.dot(v2);
|
||||
|
||||
@@ -25,7 +25,6 @@ const OBJECT_RADIUS: f32 = 64.0;
|
||||
const SECTION_LEN: f32 = 400.0;
|
||||
const DIFFICULTY_MULTIPLIER: f32 = 0.0675;
|
||||
const NORMALIZED_RADIUS: f32 = 52.0;
|
||||
const TIME_PREEMPT: f32 = 600.0; // TODO: Check mod influences
|
||||
const STACK_DISTANCE: f32 = 3.0;
|
||||
|
||||
/// Star calculation for osu!standard maps.
|
||||
@@ -53,6 +52,16 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
|
||||
return StarResult::Osu(diff_attributes);
|
||||
}
|
||||
|
||||
let mut raw_ar = map.ar;
|
||||
|
||||
if mods.hr() {
|
||||
raw_ar *= 1.4;
|
||||
} else if mods.ez() {
|
||||
raw_ar *= 0.5;
|
||||
}
|
||||
|
||||
let time_preempt = difficulty_range_ar(raw_ar);
|
||||
|
||||
let section_len = SECTION_LEN * map_attributes.clock_rate;
|
||||
let scale = (1.0 - 0.7 * (map_attributes.cs - 5.0) / 5.0) / 2.0;
|
||||
let radius = OBJECT_RADIUS * scale;
|
||||
@@ -75,6 +84,7 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
|
||||
h,
|
||||
map,
|
||||
radius,
|
||||
scaling_factor,
|
||||
&mut ticks_buf,
|
||||
&mut diff_attributes,
|
||||
&mut slider_state,
|
||||
@@ -82,10 +92,12 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
|
||||
})
|
||||
.collect();
|
||||
|
||||
let stack_threshold = time_preempt * map.stack_leniency;
|
||||
|
||||
if map.version >= 6 {
|
||||
stacking(&mut hit_objects, map.stack_leniency, TIME_PREEMPT);
|
||||
stacking(&mut hit_objects, stack_threshold);
|
||||
} else {
|
||||
old_stacking(&mut hit_objects, map.stack_leniency, TIME_PREEMPT);
|
||||
old_stacking(&mut hit_objects, stack_threshold);
|
||||
}
|
||||
|
||||
let mut hit_objects = hit_objects.into_iter().map(|mut h| {
|
||||
@@ -194,6 +206,16 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
return Strains::default();
|
||||
}
|
||||
|
||||
let mut raw_ar = map.ar;
|
||||
|
||||
if mods.hr() {
|
||||
raw_ar *= 1.4;
|
||||
} else if mods.ez() {
|
||||
raw_ar *= 0.5;
|
||||
}
|
||||
|
||||
let time_preempt = difficulty_range_ar(raw_ar);
|
||||
|
||||
let section_len = SECTION_LEN * map_attributes.clock_rate;
|
||||
let scale = (1.0 - 0.7 * (map_attributes.cs - 5.0) / 5.0) / 2.0;
|
||||
let radius = OBJECT_RADIUS * scale;
|
||||
@@ -215,6 +237,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
h,
|
||||
map,
|
||||
radius,
|
||||
scaling_factor,
|
||||
&mut ticks_buf,
|
||||
&mut diff_attributes,
|
||||
&mut slider_state,
|
||||
@@ -222,10 +245,12 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let stack_threshold = time_preempt * map.stack_leniency;
|
||||
|
||||
if map.version >= 6 {
|
||||
stacking(&mut hit_objects, map.stack_leniency, TIME_PREEMPT);
|
||||
stacking(&mut hit_objects, stack_threshold);
|
||||
} else {
|
||||
old_stacking(&mut hit_objects, map.stack_leniency, TIME_PREEMPT);
|
||||
old_stacking(&mut hit_objects, stack_threshold);
|
||||
}
|
||||
|
||||
let mut hit_objects = hit_objects.into_iter().map(|mut h| {
|
||||
@@ -316,12 +341,10 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
}
|
||||
}
|
||||
|
||||
fn stacking(hit_objects: &mut [OsuObject], stack_leniency: f32, time_preempt: f32) {
|
||||
fn stacking(hit_objects: &mut [OsuObject], stack_threshold: f32) {
|
||||
let mut extended_start_idx = 0;
|
||||
let extended_end_idx = hit_objects.len() - 1;
|
||||
|
||||
let stack_threshold = time_preempt * stack_leniency; // TODO: Calculate outside?
|
||||
|
||||
for mut i in (1..=extended_end_idx).rev() {
|
||||
let mut n = i;
|
||||
|
||||
@@ -380,16 +403,15 @@ fn stacking(hit_objects: &mut [OsuObject], stack_leniency: f32, time_preempt: f3
|
||||
}
|
||||
}
|
||||
|
||||
fn old_stacking(hit_objects: &mut [OsuObject], stack_leniency: f32, time_preempt: f32) {
|
||||
let stack_threshold = time_preempt * stack_leniency; // TODO: Calculate outside?
|
||||
|
||||
fn old_stacking(hit_objects: &mut [OsuObject], stack_threshold: f32) {
|
||||
for i in 0..hit_objects.len() {
|
||||
if hit_objects[i].stack_height != 0.0 && !hit_objects[i].is_slider() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut start_time = hit_objects[i].end_time();
|
||||
let end_pos = hit_objects[i].end_pos(); // FIXME: Wrong for sliders? Position at 100% progress.
|
||||
let end_pos = hit_objects[i].end_pos();
|
||||
|
||||
let mut slider_stack = 0.0;
|
||||
|
||||
for j in i + 1..hit_objects.len() {
|
||||
@@ -409,6 +431,15 @@ fn old_stacking(hit_objects: &mut [OsuObject], stack_leniency: f32, time_preempt
|
||||
}
|
||||
}
|
||||
|
||||
const OSU_AR_MAX: f32 = 450.0;
|
||||
const OSU_AR_AVG: f32 = 1200.0;
|
||||
const OSU_AR_MIN: f32 = 1800.0;
|
||||
|
||||
#[inline]
|
||||
fn difficulty_range_ar(ar: f32) -> f32 {
|
||||
crate::difficulty_range(ar, OSU_AR_MAX, OSU_AR_AVG, OSU_AR_MIN)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::super::OsuPP;
|
||||
@@ -416,9 +447,9 @@ mod tests {
|
||||
use std::fs::File;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
// #[ignore]
|
||||
fn all_included_single() {
|
||||
let file = match File::open("./maps/295.osu") {
|
||||
let file = match File::open("./maps/2514909.osu") {
|
||||
Ok(file) => file,
|
||||
Err(why) => panic!("Could not open file: {}", why),
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ enum OsuObjectKind {
|
||||
Slider {
|
||||
end_time: f32,
|
||||
end_pos: Pos2,
|
||||
lazy_end_pos: Pos2,
|
||||
travel_dist: f32,
|
||||
},
|
||||
Spinner {
|
||||
@@ -29,6 +30,7 @@ impl OsuObject {
|
||||
h: &HitObject,
|
||||
map: &Beatmap,
|
||||
radius: f32,
|
||||
scaling_factor: f32,
|
||||
ticks: &mut Vec<f32>,
|
||||
attributes: &mut DifficultyAttributes,
|
||||
slider_state: &mut SliderState,
|
||||
@@ -54,7 +56,7 @@ impl OsuObject {
|
||||
path_type,
|
||||
} => {
|
||||
// Key values which are computed here
|
||||
let mut end_pos = h.pos;
|
||||
let mut lazy_end_pos = h.pos;
|
||||
let mut travel_dist = 0.0;
|
||||
|
||||
// Responsible for timing point values
|
||||
@@ -107,12 +109,12 @@ impl OsuObject {
|
||||
let curr_dist = pixel_len * progress;
|
||||
let curr_pos = curve.point_at_distance(curr_dist);
|
||||
|
||||
let diff = curr_pos - end_pos;
|
||||
let diff = curr_pos - lazy_end_pos;
|
||||
let mut dist = diff.length();
|
||||
|
||||
if dist > approx_follow_circle_radius {
|
||||
dist -= approx_follow_circle_radius;
|
||||
end_pos += diff.normalize() * dist;
|
||||
lazy_end_pos += diff.normalize() * dist;
|
||||
travel_dist += dist;
|
||||
}
|
||||
};
|
||||
@@ -163,6 +165,10 @@ impl OsuObject {
|
||||
|
||||
ticks.clear();
|
||||
|
||||
travel_dist *= scaling_factor;
|
||||
|
||||
let end_pos = curve.point_at_distance(*pixel_len);
|
||||
|
||||
Self {
|
||||
time: h.start_time,
|
||||
pos: h.pos,
|
||||
@@ -170,6 +176,7 @@ impl OsuObject {
|
||||
kind: OsuObjectKind::Slider {
|
||||
end_time: final_span_end_time,
|
||||
end_pos,
|
||||
lazy_end_pos,
|
||||
travel_dist,
|
||||
},
|
||||
}
|
||||
@@ -217,6 +224,14 @@ impl OsuObject {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn lazy_end_pos(&self) -> Pos2 {
|
||||
match &self.kind {
|
||||
OsuObjectKind::Circle | OsuObjectKind::Spinner { .. } => self.pos,
|
||||
OsuObjectKind::Slider { lazy_end_pos, .. } => *lazy_end_pos,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_circle(&self) -> bool {
|
||||
matches!(self.kind, OsuObjectKind::Circle)
|
||||
|
||||
@@ -68,6 +68,7 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
|
||||
h,
|
||||
map,
|
||||
radius,
|
||||
scaling_factor,
|
||||
&mut ticks_buf,
|
||||
&mut diff_attributes,
|
||||
&mut slider_state,
|
||||
@@ -186,6 +187,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
h,
|
||||
map,
|
||||
radius,
|
||||
scaling_factor,
|
||||
&mut ticks_buf,
|
||||
&mut diff_attributes,
|
||||
&mut slider_state,
|
||||
@@ -278,7 +280,7 @@ mod tests {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn no_leniency_single() {
|
||||
let file = match File::open("./maps/295.osu") {
|
||||
let file = match File::open("./maps/2514909.osu") {
|
||||
Ok(file) => file,
|
||||
Err(why) => panic!("Could not open file: {}", why),
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ impl OsuObject {
|
||||
h: &HitObject,
|
||||
map: &Beatmap,
|
||||
radius: f32,
|
||||
scaling_factor: f32,
|
||||
ticks: &mut Vec<f32>,
|
||||
attributes: &mut DifficultyAttributes,
|
||||
slider_state: &mut SliderState,
|
||||
@@ -151,6 +152,8 @@ impl OsuObject {
|
||||
|
||||
ticks.clear();
|
||||
|
||||
travel_dist *= scaling_factor;
|
||||
|
||||
Self {
|
||||
time: h.start_time,
|
||||
pos: h.pos,
|
||||
|
||||
+12
-10
@@ -14,12 +14,14 @@ struct MapResult {
|
||||
|
||||
#[test]
|
||||
fn osu() {
|
||||
let margin = if cfg!(feature = "no_leniency") {
|
||||
0.0025
|
||||
} else if cfg!(feature = "no_sliders_no_leniency") {
|
||||
let margin = if cfg!(feature = "no_sliders_no_leniency") {
|
||||
0.0075
|
||||
} else {
|
||||
} else if cfg!(feature = "no_leniency") {
|
||||
0.0025
|
||||
} else if cfg!(feature = "all_included") {
|
||||
0.001
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let star_margin = margin;
|
||||
@@ -48,9 +50,9 @@ fn osu() {
|
||||
assert!(
|
||||
(result.stars() - stars).abs() < star_margin * stars,
|
||||
"\nStars:\n\
|
||||
Calculated: {calculated} | Expected: {expected}\n \
|
||||
=> {margin} margin ({allowed} allowed)\n\
|
||||
[map {map} | mods {mods}]\n",
|
||||
Calculated: {calculated} | Expected: {expected}\n \
|
||||
=> {margin} margin ({allowed} allowed)\n\
|
||||
[map {map} | mods {mods}]\n",
|
||||
calculated = result.stars(),
|
||||
expected = stars,
|
||||
margin = (result.stars() - stars).abs(),
|
||||
@@ -62,9 +64,9 @@ fn osu() {
|
||||
assert!(
|
||||
(result.pp() - pp).abs() < pp_margin * pp,
|
||||
"\nPP:\n\
|
||||
Calculated: {calculated} | Expected: {expected}\n \
|
||||
=> {margin} margin ({allowed} allowed)\n\
|
||||
[map {map} | mods {mods}]\n",
|
||||
Calculated: {calculated} | Expected: {expected}\n \
|
||||
=> {margin} margin ({allowed} allowed)\n\
|
||||
[map {map} | mods {mods}]\n",
|
||||
calculated = result.pp(),
|
||||
expected = pp,
|
||||
margin = (result.pp() - pp).abs(),
|
||||
|
||||
Reference in New Issue
Block a user