diff --git a/bathbot/src/active/impls/map.rs b/bathbot/src/active/impls/map.rs index c7552a5a..73f03f60 100644 --- a/bathbot/src/active/impls/map.rs +++ b/bathbot/src/active/impls/map.rs @@ -105,26 +105,27 @@ impl IActiveMessage for MapPagination { let creator_fut = creator_name(map, &self.mapset); let (map_res, gd_creator) = tokio::join!(map_fut, creator_fut); - let mut rosu_map = map_res.wrap_err("Failed to get pp map")?; + let rosu_map = map_res.wrap_err("Failed to get pp map")?; - if let Some(ar_) = self.attrs.ar { - rosu_map.ar = ar_ as f32; + let mut attrs_builder = rosu_map.attributes(); + + if let Some(ar) = self.attrs.ar { + attrs_builder.ar(ar as f32, false); } - if let Some(cs_) = self.attrs.cs { - rosu_map.cs = cs_ as f32; + if let Some(cs) = self.attrs.cs { + attrs_builder.cs(cs as f32, false); } - if let Some(hp_) = self.attrs.hp { - rosu_map.hp = hp_ as f32; + if let Some(hp) = self.attrs.hp { + attrs_builder.hp(hp as f32, false); } - if let Some(od_) = self.attrs.od { - rosu_map.od = od_ as f32; + if let Some(od) = self.attrs.od { + attrs_builder.od(od as f32, false); } - let map_attrs = rosu_map - .attributes() + let map_attrs = attrs_builder .mods(&self.mods) .clock_rate(clock_rate) .build() @@ -552,13 +553,12 @@ impl IActiveMessage for MapPagination { let mods = match mods_res { Some(Ok(value)) => Some(value), Some(Err(_)) => { - debug!(input, "Failed to parse simulate mods"); + debug!(input, "Failed to parse map mods"); return Ok(()); } None => None, }; - debug!(?mods, "Matched mods"); match mods.map(|mods| mods.try_with_mode(map.mode)) { Some(Some(mods)) if mods.is_valid() => self.mods = mods.into(), diff --git a/bathbot/src/active/impls/simulate/mod.rs b/bathbot/src/active/impls/simulate/mod.rs index 763534cf..a24345d4 100644 --- a/bathbot/src/active/impls/simulate/mod.rs +++ b/bathbot/src/active/impls/simulate/mod.rs @@ -18,6 +18,7 @@ use eyre::{ContextCompat, Report, Result}; use rosu_pp::{ Beatmap, model::{ + beatmap::BeatmapAttributesBuilder, hit_object::{HitObjectKind, HoldNote, Spinner}, mode::GameMode as Mode, }, @@ -772,7 +773,14 @@ impl SimulateMap { let map = &map.pp_map; let bits = mods.bits(); - let mut builder = map.attributes(); + // Using `.map()` would clamp AR/OD to [0, 10] to match lazer, + // but users can specify custom attributes that may exceed 10. + let mut builder = BeatmapAttributesBuilder::default(); + builder.mode(map.mode, map.is_convert); + builder.ar(map.ar, false); + builder.od(map.od, false); + builder.cs(map.cs, false); + builder.hp(map.hp, false); if let Some(clock_rate) = clock_rate.or_else(|| mods.clock_rate()) { builder.clock_rate(clock_rate); diff --git a/bathbot/src/util/osu.rs b/bathbot/src/util/osu.rs index 27ad2134..34b70bec 100644 --- a/bathbot/src/util/osu.rs +++ b/bathbot/src/util/osu.rs @@ -22,8 +22,8 @@ use image::{ DynamicImage, GenericImage, GenericImageView, ImageOutputFormat, imageops::FilterType, }; use rosu_pp::{ - any::DifficultyAttributes, catch::CatchPerformance, osu::OsuPerformance, - taiko::TaikoPerformance, + any::DifficultyAttributes, catch::CatchPerformance, model::beatmap::BeatmapAttributesBuilder, + osu::OsuPerformance, taiko::TaikoPerformance, }; use rosu_v2::{ model::mods::GameMods, @@ -718,7 +718,15 @@ impl Display for MapInfo<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { let mods = self.mods.map(GameMods::to_owned).unwrap_or_default(); - let mut builder = self.map.attributes(); + // Using `.map()` would clamp AR/OD to [0, 10] to match lazer, + // but users can specify custom attributes that may exceed 10. + let mut builder = BeatmapAttributesBuilder::default(); + let pp_map = &self.map.pp_map; + builder.mode(pp_map.mode, pp_map.is_convert); + builder.ar(pp_map.ar, false); + builder.od(pp_map.od, false); + builder.cs(pp_map.cs, false); + builder.hp(pp_map.hp, false); let clock_rate = self .clock_rate