various minor adjustments
This commit is contained in:
+9
-1
@@ -135,7 +135,7 @@ impl<'map> ManiaStars<'map> {
|
||||
let ManiaResult { strain, .. } = calculate_result(self);
|
||||
|
||||
ManiaStrains {
|
||||
section_len: SECTION_LEN * clock_rate, // TODO: clock_rate correct here?
|
||||
section_len: SECTION_LEN * clock_rate,
|
||||
strains: strain.strain_peaks,
|
||||
}
|
||||
}
|
||||
@@ -224,6 +224,14 @@ pub struct ManiaDifficultyAttributes {
|
||||
pub max_combo: usize,
|
||||
}
|
||||
|
||||
impl ManiaDifficultyAttributes {
|
||||
/// Return the maximum combo.
|
||||
#[inline]
|
||||
pub fn max_combo(&self) -> usize {
|
||||
self.max_combo
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of a performance calculation on an osu!mania map.
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
pub struct ManiaPerformanceAttributes {
|
||||
|
||||
+4
-6
@@ -5,7 +5,6 @@ use crate::{
|
||||
Beatmap, DifficultyAttributes, GameMode, HitResultPriority, Mods, OsuPP, PerformanceAttributes,
|
||||
};
|
||||
|
||||
// TODO: update
|
||||
/// Performance calculator on osu!mania maps.
|
||||
///
|
||||
/// # Example
|
||||
@@ -124,7 +123,7 @@ impl<'map> ManiaPP<'map> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify the accuracy of a play between `0` and `100`.
|
||||
/// Specify the accuracy of a play between `0.0` and `100.0`.
|
||||
/// This will be used to generate matching hitresults.
|
||||
#[inline]
|
||||
pub fn accuracy(mut self, acc: f64) -> Self {
|
||||
@@ -252,7 +251,6 @@ impl<'map> ManiaPP<'map> {
|
||||
let n_misses = self.n_misses.unwrap_or(0);
|
||||
|
||||
if let Some(acc) = self.acc {
|
||||
// TODO: test
|
||||
let target_total = (acc * (n_objects * 6) as f64).round() as usize;
|
||||
|
||||
match (self.n320, self.n300, self.n200, self.n100, self.n50) {
|
||||
@@ -530,11 +528,11 @@ impl ManiaPpInner {
|
||||
}
|
||||
|
||||
fn compute_difficulty_value(&self) -> f64 {
|
||||
// Star rating to pp curve
|
||||
// * Star rating to pp curve
|
||||
(self.attrs.stars - 0.15).max(0.05).powf(2.2)
|
||||
// From 80% accuracy, 1/20th of total pp is awarded per additional 1% accuracy
|
||||
// * From 80% accuracy, 1/20th of total pp is awarded per additional 1% accuracy
|
||||
* (5.0 * self.calculate_custom_accuracy() - 4.0).max(0.0)
|
||||
// Length bonus, capped at 1500 notes
|
||||
// * Length bonus, capped at 1500 notes
|
||||
* (1.0 + 0.1 * (self.total_hits() / 1500.0).min(1.0))
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,8 @@ pub(crate) trait StrainSkill: Sized + Skill {
|
||||
fn strain_value_at(&mut self, curr: &ManiaDifficultyObject) -> f64;
|
||||
|
||||
fn process(&mut self, curr: &ManiaDifficultyObject, diff_objects: &[ManiaDifficultyObject]) {
|
||||
// The first object doesn't generate a strain, so we begin with an incremented section end
|
||||
// * The first object doesn't generate a strain, so we begin with an incremented section end
|
||||
if curr.idx == 0 {
|
||||
// currentSectionEnd = Math.Ceiling(current.StartTime / SectionLength) * SectionLength;
|
||||
*self.curr_section_end_mut() = (curr.start_time / SECTION_LEN).ceil() * SECTION_LEN;
|
||||
}
|
||||
|
||||
@@ -72,14 +71,14 @@ pub(crate) trait StrainSkill: Sized + Skill {
|
||||
let mut difficulty = 0.0;
|
||||
let mut weight = 1.0;
|
||||
|
||||
// Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
|
||||
// These sections will not contribute to the difficulty.
|
||||
// * Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
|
||||
// * These sections will not contribute to the difficulty.
|
||||
let mut peaks = self.get_curr_strain_peaks();
|
||||
peaks.retain(|&peak| peak > 0.0);
|
||||
peaks.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal));
|
||||
|
||||
// Difficulty is the weighted sum of the highest strains from every section.
|
||||
// We're sorting from highest to lowest strain.
|
||||
// * Difficulty is the weighted sum of the highest strains from every section.
|
||||
// * We're sorting from highest to lowest strain.
|
||||
for strain in peaks {
|
||||
difficulty += strain * weight;
|
||||
weight *= Self::DECAY_WEIGHT;
|
||||
|
||||
+31
-20
@@ -43,10 +43,12 @@ impl Strain {
|
||||
}
|
||||
|
||||
impl Skill for Strain {
|
||||
#[inline]
|
||||
fn process(&mut self, curr: &ManiaDifficultyObject, diff_objects: &[ManiaDifficultyObject]) {
|
||||
<Self as StrainSkill>::process(self, curr, diff_objects)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn difficulty_value(self) -> f64 {
|
||||
<Self as StrainSkill>::difficulty_value(self)
|
||||
}
|
||||
@@ -55,30 +57,37 @@ impl Skill for Strain {
|
||||
impl StrainSkill for Strain {
|
||||
const DECAY_WEIGHT: f64 = 0.9;
|
||||
|
||||
#[inline]
|
||||
fn curr_section_end(&self) -> f64 {
|
||||
self.curr_section_end
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn curr_section_end_mut(&mut self) -> &mut f64 {
|
||||
&mut self.curr_section_end
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn curr_section_peak(&self) -> f64 {
|
||||
self.curr_section_peak
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn curr_section_peak_mut(&mut self) -> &mut f64 {
|
||||
&mut self.curr_section_peak
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strain_peaks_mut(&mut self) -> &mut Vec<f64> {
|
||||
&mut self.strain_peaks
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn strain_value_at(&mut self, curr: &ManiaDifficultyObject) -> f64 {
|
||||
<Self as StrainDecaySkill>::strain_value_at(self, curr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn calculate_initial_strain(
|
||||
&self,
|
||||
time: f64,
|
||||
@@ -93,10 +102,12 @@ impl StrainDecaySkill for Strain {
|
||||
const SKILL_MULTIPLIER: f64 = 1.0;
|
||||
const STRAIN_DECAY_BASE: f64 = 1.0;
|
||||
|
||||
#[inline]
|
||||
fn curr_strain(&self) -> f64 {
|
||||
self.curr_strain
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn curr_strain_mut(&mut self) -> &mut f64 {
|
||||
&mut self.curr_strain
|
||||
}
|
||||
@@ -108,19 +119,19 @@ impl StrainDecaySkill for Strain {
|
||||
let col = mania_curr.base_column;
|
||||
let mut is_overlapping = false;
|
||||
|
||||
// Lowest value we can assume with the current information
|
||||
// * Lowest value we can assume with the current information
|
||||
let mut closest_end_time = (end_time - start_time).abs();
|
||||
// Factor to all additional strains in case something else is held
|
||||
// * Factor to all additional strains in case something else is held
|
||||
let mut hold_factor = 1.0;
|
||||
// Addition to the current note in case it's a hold and has to be released awkwardly
|
||||
// * Addition to the current note in case it's a hold and has to be released awkwardly
|
||||
let mut hold_addition = 0.0;
|
||||
|
||||
for i in 0..self.end_times.len() {
|
||||
// The current note is overlapped if a previous note or end is overlapping the current note body
|
||||
// * The current note is overlapped if a previous note or end is overlapping the current note body
|
||||
is_overlapping |=
|
||||
self.end_times[i] > start_time + 1.0 && end_time > self.end_times[i] + 1.0;
|
||||
|
||||
// We give a slight bonus to everything if something is held meanwhile
|
||||
// * We give a slight bonus to everything if something is held meanwhile
|
||||
if self.end_times[i] > end_time + 1.0 {
|
||||
hold_factor = 1.25;
|
||||
}
|
||||
@@ -128,22 +139,22 @@ impl StrainDecaySkill for Strain {
|
||||
closest_end_time = (end_time - self.end_times[i]).abs().min(closest_end_time);
|
||||
}
|
||||
|
||||
// The hold addition is given if there was an overlap, however it is only valid if there are no other note with a similar ending.
|
||||
// Releasing multiple notes is just as easy as releasing 1. Nerfs the hold addition by half if the closest release is release_threshold away.
|
||||
// holdAddition
|
||||
// ^
|
||||
// 1.0 + - - - - - -+-----------
|
||||
// | /
|
||||
// 0.5 + - - - - -/ Sigmoid Curve
|
||||
// | /|
|
||||
// 0.0 +--------+-+---------------> Release Difference / ms
|
||||
// release_threshold
|
||||
// * The hold addition is given if there was an overlap, however it is only valid if there are no other note with a similar ending.
|
||||
// * Releasing multiple notes is just as easy as releasing 1. Nerfs the hold addition by half if the closest release is release_threshold away.
|
||||
// * holdAddition
|
||||
// * ^
|
||||
// * 1.0 + - - - - - -+-----------
|
||||
// * | /
|
||||
// * 0.5 + - - - - -/ Sigmoid Curve
|
||||
// * | /|
|
||||
// * 0.0 +--------+-+---------------> Release Difference / ms
|
||||
// * release_threshold
|
||||
if is_overlapping {
|
||||
hold_addition =
|
||||
(1.0 + (0.5 * (Self::RELEASE_THRESHOLD - closest_end_time)).exp()).recip();
|
||||
}
|
||||
|
||||
// Decay and increase individualStrains in own column
|
||||
// * Decay and increase individualStrains in own column
|
||||
self.individual_strains[col] = Self::apply_decay(
|
||||
self.individual_strains[col],
|
||||
start_time - self.start_times[col],
|
||||
@@ -151,14 +162,14 @@ impl StrainDecaySkill for Strain {
|
||||
);
|
||||
self.individual_strains[col] += 2.0 * hold_factor;
|
||||
|
||||
// For notes at the same time (in a chord), the individualStrain should be the hardest individualStrain out of those columns
|
||||
// * For notes at the same time (in a chord), the individualStrain should be the hardest individualStrain out of those columns
|
||||
self.individual_strain = if mania_curr.delta_time <= 1.0 {
|
||||
self.individual_strain.max(self.individual_strains[col])
|
||||
} else {
|
||||
self.individual_strains[col]
|
||||
};
|
||||
|
||||
// Decay and increase overallStrain
|
||||
// * Decay and increase overallStrain
|
||||
self.overall_strain = Self::apply_decay(
|
||||
self.overall_strain,
|
||||
curr.delta_time,
|
||||
@@ -166,11 +177,11 @@ impl StrainDecaySkill for Strain {
|
||||
);
|
||||
self.overall_strain += (1.0 + hold_addition) * hold_factor;
|
||||
|
||||
// Update startTimes and endTimes arrays
|
||||
// * Update startTimes and endTimes arrays
|
||||
self.start_times[col] = start_time;
|
||||
self.end_times[col] = end_time;
|
||||
|
||||
// By subtracting CurrentStrain, this skill effectively only considers the maximum strain of any one hitobject within each strain section.
|
||||
// * By subtracting CurrentStrain, this skill effectively only considers the maximum strain of any one hitobject within each strain section.
|
||||
self.individual_strain + self.overall_strain - self.curr_strain
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user