feat: use rosu-mods (#36)

* use rosu-mods

* apply values from DifficultyAdjust mod

* minor doc addition

* consider Blinds mod in perf calc
This commit is contained in:
Badewanne3
2024-07-08 11:35:07 +02:00
committed by GitHub
parent 5c951b8bd4
commit 26547d7dea
19 changed files with 576 additions and 238 deletions
-1
View File
@@ -7,7 +7,6 @@ use crate::{
object::{OsuObject, OsuObjectKind},
OsuBeatmap,
},
util::mods::Mods,
Difficulty,
};
+2 -3
View File
@@ -2,14 +2,13 @@ use std::{cmp, pin::Pin};
use crate::{
any::difficulty::{skills::Skill, Difficulty},
model::beatmap::BeatmapAttributes,
model::{beatmap::BeatmapAttributes, mods::GameMods},
osu::{
convert::convert_objects,
difficulty::{object::OsuDifficultyObject, scaling_factor::ScalingFactor},
object::OsuObject,
performance::PERFORMANCE_BASE_MULTIPLIER,
},
util::mods::Mods,
};
use self::skills::OsuSkills;
@@ -146,7 +145,7 @@ impl DifficultyValues {
/// Process the difficulty values and store the results in `attrs`.
pub fn eval(
attrs: &mut OsuDifficultyAttributes,
mods: u32,
mods: &GameMods,
aim_difficulty_value: f64,
aim_no_sliders_difficulty_value: f64,
speed_difficulty_value: f64,
+3 -2
View File
@@ -5,8 +5,9 @@ use crate::{
object::IDifficultyObject,
skills::{strain_decay, ISkill, Skill, StrainSkill},
},
model::mods::GameMods,
osu::{difficulty::object::OsuDifficultyObject, object::OsuObjectKind},
util::{mods::Mods, strains_vec::StrainsVec},
util::strains_vec::StrainsVec,
};
use super::strain::OsuStrainSkill;
@@ -22,7 +23,7 @@ pub struct Flashlight {
}
impl Flashlight {
pub fn new(mods: u32, radius: f64, time_preempt: f64, time_fade_in: f64) -> Self {
pub fn new(mods: &GameMods, radius: f64, time_preempt: f64, time_fade_in: f64) -> Self {
let scaling_factor = 52.0 / radius;
Self {
+5 -2
View File
@@ -1,4 +1,7 @@
use crate::{model::beatmap::BeatmapAttributes, osu::object::OsuObject, util::mods::Mods};
use crate::{
model::{beatmap::BeatmapAttributes, mods::GameMods},
osu::object::OsuObject,
};
use self::{aim::Aim, flashlight::Flashlight, speed::Speed};
@@ -18,7 +21,7 @@ pub struct OsuSkills {
impl OsuSkills {
pub fn new(
mods: u32,
mods: &GameMods,
scaling_factor: &ScalingFactor,
map_attrs: &BeatmapAttributes,
time_preempt: f64,
+33 -12
View File
@@ -6,8 +6,9 @@ use crate::{
any::{Difficulty, HitResultPriority, IntoModePerformance, IntoPerformance, Performance},
catch::CatchPerformance,
mania::ManiaPerformance,
model::mods::GameMods,
taiko::TaikoPerformance,
util::{float_ext::FloatExt, map_or_attrs::MapOrAttrs, mods::Mods},
util::{float_ext::FloatExt, map_or_attrs::MapOrAttrs},
};
use super::{
@@ -118,10 +119,17 @@ impl<'map> OsuPerformance<'map> {
}
}
/// Specify mods through their bit values.
/// Specify mods.
///
/// Accepted types are
/// - `u32`
/// - [`rosu_mods::GameModsLegacy`]
/// - [`rosu_mods::GameMods`]
/// - [`rosu_mods::GameModsIntermode`]
/// - [`&rosu_mods::GameModsIntermode`](rosu_mods::GameModsIntermode)
///
/// See <https://github.com/ppy/osu-api/wiki#mods>
pub const fn mods(mut self, mods: u32) -> Self {
pub fn mods(mut self, mods: impl Into<GameMods>) -> Self {
self.difficulty = self.difficulty.mods(mods);
self
@@ -172,7 +180,7 @@ impl<'map> OsuPerformance<'map> {
}
/// Use the specified settings of the given [`Difficulty`].
pub const fn difficulty(mut self, difficulty: Difficulty) -> Self {
pub fn difficulty(mut self, difficulty: Difficulty) -> Self {
self.difficulty = difficulty;
self
@@ -185,7 +193,7 @@ impl<'map> OsuPerformance<'map> {
/// `passed_objects`, you should use [`OsuGradualPerformance`].
///
/// [`OsuGradualPerformance`]: crate::osu::OsuGradualPerformance
pub const fn passed_objects(mut self, passed_objects: u32) -> Self {
pub fn passed_objects(mut self, passed_objects: u32) -> Self {
self.difficulty = self.difficulty.passed_objects(passed_objects);
self
@@ -522,15 +530,15 @@ impl<'map, T: IntoModePerformance<'map, Osu>> From<T> for OsuPerformance<'map> {
pub const PERFORMANCE_BASE_MULTIPLIER: f64 = 1.14;
struct OsuPerformanceInner {
struct OsuPerformanceInner<'mods> {
attrs: OsuDifficultyAttributes,
mods: u32,
mods: &'mods GameMods,
acc: f64,
state: OsuScoreState,
effective_miss_count: f64,
}
impl OsuPerformanceInner {
impl OsuPerformanceInner<'_> {
fn calculate(mut self) -> OsuPerformanceAttributes {
let total_hits = self.state.total_hits();
@@ -632,7 +640,13 @@ impl OsuPerformanceInner {
// * Buff for longer maps with high AR.
aim_value *= 1.0 + ar_factor * len_bonus;
if self.mods.hd() {
if self.mods.bl() {
aim_value *= 1.3
+ (total_hits
* (0.0016 / (1.0 + 2.0 * self.effective_miss_count))
* self.acc.powf(16.0))
* (1.0 - 0.003 * self.attrs.hp * self.attrs.hp);
} else if self.mods.hd() {
// * We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
aim_value *= 1.0 + 0.04 * (12.0 - self.attrs.ar);
}
@@ -695,7 +709,11 @@ impl OsuPerformanceInner {
// * Buff for longer maps with high AR.
speed_value *= 1.0 + ar_factor * len_bonus;
if self.mods.hd() {
if self.mods.bl() {
// * Increasing the speed value by object count for Blinds isn't
// * ideal, so the minimum buff is given.
speed_value *= 1.12;
} else if self.mods.hd() {
// * We want to give more reward for lower AR when it comes to aim and HD.
// * This nerfs high AR and buffs lower AR.
speed_value *= 1.0 + 0.04 * (12.0 - self.attrs.ar);
@@ -764,8 +782,11 @@ impl OsuPerformanceInner {
.powf(0.3)
.min(1.15);
// * Increasing the accuracy value by object count for Blinds isn't ideal, so the minimum buff is given.
if self.mods.hd() {
// * Increasing the accuracy value by object count for Blinds isn't
// * ideal, so the minimum buff is given.
if self.mods.bl() {
acc_value *= 1.14;
} else if self.mods.hd() {
acc_value *= 1.08;
}