f32 -> f64 & osu_precise fixes + update
This commit is contained in:
@@ -6,9 +6,9 @@ pub(crate) struct DifficultyObject<'o> {
|
||||
pub(crate) idx: usize,
|
||||
pub(crate) base: &'o HitObject,
|
||||
pub(crate) prev: &'o HitObject,
|
||||
pub(crate) delta: f32,
|
||||
pub(crate) delta: f64,
|
||||
pub(crate) rhythm: &'static HitObjectRhythm,
|
||||
pub(crate) start_time: f32,
|
||||
pub(crate) start_time: f64,
|
||||
}
|
||||
|
||||
impl<'o> DifficultyObject<'o> {
|
||||
@@ -18,7 +18,7 @@ impl<'o> DifficultyObject<'o> {
|
||||
base: &'o HitObject,
|
||||
prev: &'o HitObject,
|
||||
prev_prev: &HitObject,
|
||||
clock_rate: f32,
|
||||
clock_rate: f64,
|
||||
) -> Self {
|
||||
let delta = (base.start_time - prev.start_time) / clock_rate;
|
||||
let rhythm = closest_rhythm(delta, prev, prev_prev, clock_rate);
|
||||
|
||||
@@ -53,8 +53,8 @@ static COMMON_RHYTHMS: [HitObjectRhythm; 9] = [
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct HitObjectRhythm {
|
||||
id: u8,
|
||||
ratio: f32,
|
||||
pub(crate) difficulty: f32,
|
||||
ratio: f64,
|
||||
pub(crate) difficulty: f64,
|
||||
}
|
||||
|
||||
impl PartialEq for HitObjectRhythm {
|
||||
@@ -68,10 +68,10 @@ impl Eq for HitObjectRhythm {}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn closest_rhythm(
|
||||
delta_time: f32,
|
||||
delta_time: f64,
|
||||
last: &HitObject,
|
||||
last_last: &HitObject,
|
||||
clock_rate: f32,
|
||||
clock_rate: f64,
|
||||
) -> &'static HitObjectRhythm {
|
||||
let prev_len = (last.start_time - last_last.start_time) / clock_rate;
|
||||
let ratio = delta_time / prev_len;
|
||||
|
||||
+15
-15
@@ -21,13 +21,13 @@ use stamina_cheese::StaminaCheeseDetector;
|
||||
use crate::{Beatmap, Mods, Strains};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::f32::consts::PI;
|
||||
use std::f64::consts::PI;
|
||||
|
||||
const SECTION_LEN: f32 = 400.0;
|
||||
const SECTION_LEN: f64 = 400.0;
|
||||
|
||||
const COLOR_SKILL_MULTIPLIER: f32 = 0.01;
|
||||
const RHYTHM_SKILL_MULTIPLIER: f32 = 0.014;
|
||||
const STAMINA_SKILL_MULTIPLIER: f32 = 0.02;
|
||||
const COLOR_SKILL_MULTIPLIER: f64 = 0.01;
|
||||
const RHYTHM_SKILL_MULTIPLIER: f64 = 0.014;
|
||||
const STAMINA_SKILL_MULTIPLIER: f64 = 0.02;
|
||||
|
||||
/// Star calculation for osu!taiko maps.
|
||||
///
|
||||
@@ -209,7 +209,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rescale(stars: f32) -> f32 {
|
||||
fn rescale(stars: f64) -> f64 {
|
||||
if stars < 0.0 {
|
||||
stars
|
||||
} else {
|
||||
@@ -218,7 +218,7 @@ fn rescale(stars: f32) -> f32 {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simple_color_penalty(stamina: f32, color: f32) -> f32 {
|
||||
fn simple_color_penalty(stamina: f64, color: f64) -> f64 {
|
||||
if color <= 0.0 {
|
||||
0.79 - 0.25
|
||||
} else {
|
||||
@@ -226,7 +226,7 @@ fn simple_color_penalty(stamina: f32, color: f32) -> f32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn locally_combined_difficulty(skills: &[Skill], stamina_penalty: f32) -> f32 {
|
||||
fn locally_combined_difficulty(skills: &[Skill], stamina_penalty: f64) -> f64 {
|
||||
let mut peaks = Vec::with_capacity(skills[0].strain_peaks.len());
|
||||
|
||||
let iter = skills[0]
|
||||
@@ -259,7 +259,7 @@ fn locally_combined_difficulty(skills: &[Skill], stamina_penalty: f32) -> f32 {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn norm(p: f32, a: f32, b: f32, c: f32) -> f32 {
|
||||
fn norm(p: f64, a: f64, b: f64, c: f64) -> f64 {
|
||||
(a.powf(p) + b.powf(p) + c.powf(p)).powf(p.recip())
|
||||
}
|
||||
|
||||
@@ -267,28 +267,28 @@ fn norm(p: f32, a: f32, b: f32, c: f32) -> f32 {
|
||||
/// This data is necessary to calculate PP.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct DifficultyAttributes {
|
||||
pub stars: f32,
|
||||
pub stars: f64,
|
||||
}
|
||||
|
||||
/// Various data created through the pp calculation.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct PerformanceAttributes {
|
||||
pub attributes: DifficultyAttributes,
|
||||
pub pp: f32,
|
||||
pub pp_acc: f32,
|
||||
pub pp_strain: f32,
|
||||
pub pp: f64,
|
||||
pub pp_acc: f64,
|
||||
pub pp_strain: f64,
|
||||
}
|
||||
|
||||
impl PerformanceAttributes {
|
||||
/// Return the star value.
|
||||
#[inline]
|
||||
pub fn stars(&self) -> f32 {
|
||||
pub fn stars(&self) -> f64 {
|
||||
self.attributes.stars
|
||||
}
|
||||
|
||||
/// Return the performance point value.
|
||||
#[inline]
|
||||
pub fn pp(&self) -> f32 {
|
||||
pub fn pp(&self) -> f64 {
|
||||
self.pp
|
||||
}
|
||||
}
|
||||
|
||||
+22
-26
@@ -32,11 +32,11 @@ use crate::{Beatmap, Mods, PpResult, StarResult};
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct TaikoPP<'m> {
|
||||
map: &'m Beatmap,
|
||||
stars: Option<f32>,
|
||||
stars: Option<f64>,
|
||||
mods: u32,
|
||||
max_combo: usize,
|
||||
combo: Option<usize>,
|
||||
acc: f32,
|
||||
acc: f64,
|
||||
n_misses: usize,
|
||||
passed_objects: Option<usize>,
|
||||
|
||||
@@ -69,7 +69,7 @@ impl<'m> TaikoPP<'m> {
|
||||
#[inline]
|
||||
pub fn attributes(mut self, attributes: impl TaikoAttributeProvider) -> Self {
|
||||
if let Some(stars) = attributes.attributes() {
|
||||
self.stars.replace(stars);
|
||||
self.stars = Some(stars);
|
||||
}
|
||||
|
||||
self
|
||||
@@ -119,7 +119,7 @@ impl<'m> TaikoPP<'m> {
|
||||
|
||||
/// Set the accuracy between 0.0 and 100.0.
|
||||
#[inline]
|
||||
pub fn accuracy(mut self, acc: f32) -> Self {
|
||||
pub fn accuracy(mut self, acc: f64) -> Self {
|
||||
self.acc = acc / 100.0;
|
||||
self.n300.take();
|
||||
self.n100.take();
|
||||
@@ -158,7 +158,7 @@ impl<'m> TaikoPP<'m> {
|
||||
(None, None) => unreachable!(),
|
||||
};
|
||||
|
||||
self.acc = (2 * n300 + n100) as f32 / (2 * (n300 + n100 + misses)) as f32;
|
||||
self.acc = (2 * n300 + n100) as f64 / (2 * (n300 + n100 + misses)) as f64;
|
||||
}
|
||||
|
||||
let inner = TaikoPPInner {
|
||||
@@ -176,10 +176,10 @@ impl<'m> TaikoPP<'m> {
|
||||
|
||||
struct TaikoPPInner<'m> {
|
||||
map: &'m Beatmap,
|
||||
stars: f32,
|
||||
stars: f64,
|
||||
mods: u32,
|
||||
max_combo: usize,
|
||||
acc: f32,
|
||||
acc: f64,
|
||||
n_misses: usize,
|
||||
}
|
||||
|
||||
@@ -208,16 +208,16 @@ impl<'m> TaikoPPInner<'m> {
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_strain_value(&self, stars: f32) -> f32 {
|
||||
fn compute_strain_value(&self, stars: f64) -> f64 {
|
||||
let exp_base = 5.0 * (stars / 0.0075).max(1.0) - 4.0;
|
||||
let mut strain = exp_base * exp_base / 100_000.0;
|
||||
|
||||
// Longer maps are worth more
|
||||
let len_bonus = 1.0 + 0.1 * (self.max_combo as f32 / 1500.0).min(1.0);
|
||||
let len_bonus = 1.0 + 0.1 * (self.max_combo as f64 / 1500.0).min(1.0);
|
||||
strain *= len_bonus;
|
||||
|
||||
// Penalize misses exponentially
|
||||
strain *= 0.985_f32.powi(self.n_misses as i32);
|
||||
strain *= 0.985_f64.powi(self.n_misses as i32);
|
||||
|
||||
// HD bonus
|
||||
if self.mods.hd() {
|
||||
@@ -234,8 +234,8 @@ impl<'m> TaikoPPInner<'m> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn compute_accuracy_value(&self) -> f32 {
|
||||
let mut od = self.map.od;
|
||||
fn compute_accuracy_value(&self) -> f64 {
|
||||
let mut od = self.map.od as f64;
|
||||
|
||||
if self.mods.hr() {
|
||||
od *= 1.4;
|
||||
@@ -248,47 +248,43 @@ impl<'m> TaikoPPInner<'m> {
|
||||
(150.0 / hit_window).powf(1.1)
|
||||
* self.acc.powi(15)
|
||||
* 22.0
|
||||
* (self.max_combo as f32 / 1500.0).powf(0.3).min(1.15)
|
||||
* (self.max_combo as f64 / 1500.0).powf(0.3).min(1.15)
|
||||
}
|
||||
}
|
||||
|
||||
const HITWINDOW_MIN: f32 = 50.0;
|
||||
const HITWINDOW_AVG: f32 = 35.0;
|
||||
const HITWINDOW_MAX: f32 = 20.0;
|
||||
|
||||
#[inline]
|
||||
fn difficulty_range_od(od: f32) -> f32 {
|
||||
crate::difficulty_range(od, HITWINDOW_MAX, HITWINDOW_AVG, HITWINDOW_MIN)
|
||||
fn difficulty_range_od(od: f64) -> f64 {
|
||||
crate::difficulty_range(od, 20.0, 35.0, 50.0)
|
||||
}
|
||||
|
||||
pub trait TaikoAttributeProvider {
|
||||
fn attributes(self) -> Option<f32>;
|
||||
fn attributes(self) -> Option<f64>;
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for f32 {
|
||||
impl TaikoAttributeProvider for f64 {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f32> {
|
||||
fn attributes(self) -> Option<f64> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for DifficultyAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f32> {
|
||||
fn attributes(self) -> Option<f64> {
|
||||
Some(self.stars)
|
||||
}
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for PerformanceAttributes {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f32> {
|
||||
fn attributes(self) -> Option<f64> {
|
||||
Some(self.attributes.stars)
|
||||
}
|
||||
}
|
||||
|
||||
impl TaikoAttributeProvider for StarResult {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f32> {
|
||||
fn attributes(self) -> Option<f64> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Self::Taiko(attributes) = self {
|
||||
Some(attributes.stars)
|
||||
@@ -300,7 +296,7 @@ impl TaikoAttributeProvider for StarResult {
|
||||
|
||||
impl TaikoAttributeProvider for PpResult {
|
||||
#[inline]
|
||||
fn attributes(self) -> Option<f32> {
|
||||
fn attributes(self) -> Option<f64> {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Self::Taiko(attributes) = self {
|
||||
Some(attributes.attributes.stars)
|
||||
|
||||
+17
-17
@@ -2,25 +2,25 @@ use super::{DifficultyObject, SkillKind};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
const DECAY_WEIGHT: f32 = 0.9;
|
||||
const DECAY_WEIGHT: f64 = 0.9;
|
||||
|
||||
const COLOR_SKILL_MULTIPLIER: f32 = 1.0;
|
||||
const COLOR_STRAIN_DECAY_BASE: f32 = 0.4;
|
||||
const COLOR_SKILL_MULTIPLIER: f64 = 1.0;
|
||||
const COLOR_STRAIN_DECAY_BASE: f64 = 0.4;
|
||||
|
||||
const RHYTHM_SKILL_MULTIPLIER: f32 = 10.0;
|
||||
const RHYTHM_STRAIN_DECAY_BASE: f32 = 0.0;
|
||||
const RHYTHM_SKILL_MULTIPLIER: f64 = 10.0;
|
||||
const RHYTHM_STRAIN_DECAY_BASE: f64 = 0.0;
|
||||
|
||||
const STAMINA_SKILL_MULTIPLIER: f32 = 1.0;
|
||||
const STAMINA_STRAIN_DECAY_BASE: f32 = 0.4;
|
||||
const STAMINA_SKILL_MULTIPLIER: f64 = 1.0;
|
||||
const STAMINA_STRAIN_DECAY_BASE: f64 = 0.4;
|
||||
|
||||
pub(crate) struct Skill {
|
||||
pub current_strain: f32,
|
||||
current_section_peak: f32,
|
||||
pub current_strain: f64,
|
||||
current_section_peak: f64,
|
||||
|
||||
kind: SkillKind,
|
||||
pub(crate) strain_peaks: Vec<f32>,
|
||||
pub(crate) strain_peaks: Vec<f64>,
|
||||
|
||||
prev_time: Option<f32>,
|
||||
prev_time: Option<f64>,
|
||||
}
|
||||
|
||||
impl Skill {
|
||||
@@ -43,7 +43,7 @@ impl Skill {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn start_new_section_from(&mut self, time: f32) {
|
||||
pub(crate) fn start_new_section_from(&mut self, time: f64) {
|
||||
self.current_section_peak = self.peak_strain(time - self.prev_time.unwrap());
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ impl Skill {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn difficulty_value(&self, buf: &mut [f32]) -> f32 {
|
||||
pub(crate) fn difficulty_value(&self, buf: &mut [f64]) -> f64 {
|
||||
let mut difficulty = 0.0;
|
||||
let mut weight = 1.0;
|
||||
|
||||
@@ -72,7 +72,7 @@ impl Skill {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn skill_multiplier(&self) -> f32 {
|
||||
fn skill_multiplier(&self) -> f64 {
|
||||
match self.kind {
|
||||
SkillKind::Color { .. } => COLOR_SKILL_MULTIPLIER,
|
||||
SkillKind::Rhythm { .. } => RHYTHM_SKILL_MULTIPLIER,
|
||||
@@ -81,7 +81,7 @@ impl Skill {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strain_decay_base(&self) -> f32 {
|
||||
fn strain_decay_base(&self) -> f64 {
|
||||
match self.kind {
|
||||
SkillKind::Color { .. } => COLOR_STRAIN_DECAY_BASE,
|
||||
SkillKind::Rhythm { .. } => RHYTHM_STRAIN_DECAY_BASE,
|
||||
@@ -90,12 +90,12 @@ impl Skill {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn peak_strain(&self, delta_time: f32) -> f32 {
|
||||
fn peak_strain(&self, delta_time: f64) -> f64 {
|
||||
self.current_strain * self.strain_decay(delta_time)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strain_decay(&self, ms: f32) -> f32 {
|
||||
fn strain_decay(&self, ms: f64) -> f64 {
|
||||
self.strain_decay_base().powf(ms / 1000.0)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-14
@@ -2,7 +2,7 @@ use super::{DifficultyObject, HitObjectRhythm, LimitedQueue, Rim};
|
||||
|
||||
use std::ops::Index;
|
||||
|
||||
const RHYTHM_STRAIN_DECAY: f32 = 0.96;
|
||||
const RHYTHM_STRAIN_DECAY: f64 = 0.96;
|
||||
const MOST_RECENT_PATTERNS_TO_COMPARE: usize = 2;
|
||||
|
||||
const MONO_HISTORY_MAX_LEN: usize = 5;
|
||||
@@ -18,12 +18,12 @@ pub(crate) enum SkillKind {
|
||||
Rhythm {
|
||||
rhythm_history: LimitedQueue<(usize, HitObjectRhythm)>, // (idx, rhythm)
|
||||
notes_since_rhythm_change: usize,
|
||||
current_strain: f32,
|
||||
current_strain: f64,
|
||||
},
|
||||
Stamina {
|
||||
note_pair_duration_history: LimitedQueue<f32>,
|
||||
note_pair_duration_history: LimitedQueue<f64>,
|
||||
hand: u8,
|
||||
off_hand_object_duration: f32,
|
||||
off_hand_object_duration: f64,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ impl SkillKind {
|
||||
Self::Stamina {
|
||||
note_pair_duration_history: LimitedQueue::new(STAMINA_HISTORY_MAX_LEN),
|
||||
hand: right_hand as u8,
|
||||
off_hand_object_duration: f32::MAX,
|
||||
off_hand_object_duration: f64::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ impl SkillKind {
|
||||
&mut self,
|
||||
current: &DifficultyObject<'_>,
|
||||
cheese: &[bool],
|
||||
) -> f32 {
|
||||
) -> f64 {
|
||||
match self {
|
||||
Self::Color {
|
||||
mono_history,
|
||||
@@ -157,7 +157,7 @@ impl SkillKind {
|
||||
*current_strain *= RHYTHM_STRAIN_DECAY;
|
||||
*notes_since_rhythm_change += 1;
|
||||
|
||||
if current.rhythm.difficulty.abs() <= f32::EPSILON {
|
||||
if current.rhythm.difficulty.abs() <= f64::EPSILON {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@@ -250,15 +250,16 @@ impl SkillKind {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pattern_len_penalty(pattern_len: usize) -> f32 {
|
||||
let short_pattern_penalty = (0.15 * pattern_len as f32).min(1.0);
|
||||
let long_pattern_penalty = (2.5 - 0.15 * pattern_len as f32).max(0.0).min(1.0);
|
||||
fn pattern_len_penalty(pattern_len: usize) -> f64 {
|
||||
let pattern_len = pattern_len as f64;
|
||||
let short_pattern_penalty = (0.15 * pattern_len).min(1.0);
|
||||
let long_pattern_penalty = (2.5 - 0.15 * pattern_len).max(0.0).min(1.0);
|
||||
|
||||
short_pattern_penalty.min(long_pattern_penalty)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cheese_penalty(note_pair_duration: f32) -> f32 {
|
||||
fn cheese_penalty(note_pair_duration: f64) -> f64 {
|
||||
if note_pair_duration > 125.0 {
|
||||
1.0
|
||||
} else if note_pair_duration < 100.0 {
|
||||
@@ -269,7 +270,7 @@ fn cheese_penalty(note_pair_duration: f32) -> f32 {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn speed_bonus(note_pair_duration: f32) -> f32 {
|
||||
fn speed_bonus(note_pair_duration: f64) -> f64 {
|
||||
if note_pair_duration > 200.0 {
|
||||
return 0.0;
|
||||
}
|
||||
@@ -281,6 +282,6 @@ fn speed_bonus(note_pair_duration: f32) -> f32 {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn repetition_penalty(notes_since: usize) -> f32 {
|
||||
(0.032 * notes_since as f32).min(1.0)
|
||||
fn repetition_penalty(notes_since: usize) -> f64 {
|
||||
(0.032 * notes_since as f64).min(1.0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user