expose Converted::map

This commit is contained in:
MaxOhn
2024-03-02 07:00:01 +01:00
parent 59dfc109e0
commit 6eac895339
20 changed files with 73 additions and 113 deletions
+18 -37
View File
@@ -45,13 +45,13 @@ macro_rules! impl_from_mode {
( $mode:ident ) => { ( $mode:ident ) => {
impl<'a> From<Converted<'a, $mode>> for Difficulty<'a> { impl<'a> From<Converted<'a, $mode>> for Difficulty<'a> {
fn from(converted: Converted<'a, $mode>) -> Self { fn from(converted: Converted<'a, $mode>) -> Self {
Self::new_with_cow(converted.map) Self::new_with_cow(converted.into_inner())
} }
} }
impl<'a, 'b: 'a> From<&'b Converted<'a, $mode>> for Difficulty<'a> { impl<'a, 'b: 'a> From<&'b Converted<'a, $mode>> for Difficulty<'a> {
fn from(converted: &'b Converted<'a, $mode>) -> Self { fn from(converted: &'b Converted<'a, $mode>) -> Self {
Self::new(converted.map.as_ref()) Self::new(&converted)
} }
} }
}; };
@@ -73,10 +73,10 @@ impl Difficulty<'_> {
/// [`mode_or_ignore`]: Self::mode_or_ignore /// [`mode_or_ignore`]: Self::mode_or_ignore
pub fn try_mode(&mut self, mode: GameMode) -> Option<&mut Self> { pub fn try_mode(&mut self, mode: GameMode) -> Option<&mut Self> {
let map = match mode { let map = match mode {
GameMode::Osu => OsuBeatmap::try_from_ref(self.map.as_ref())?.map, GameMode::Osu => OsuBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
GameMode::Taiko => TaikoBeatmap::try_from_ref(self.map.as_ref())?.map, GameMode::Taiko => TaikoBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
GameMode::Catch => CatchBeatmap::try_from_ref(self.map.as_ref())?.map, GameMode::Catch => CatchBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
GameMode::Mania => ManiaBeatmap::try_from_ref(self.map.as_ref())?.map, GameMode::Mania => ManiaBeatmap::try_from_ref(self.map.as_ref())?.into_inner(),
}; };
if matches!(map, Cow::Owned(_)) { if matches!(map, Cow::Owned(_)) {
@@ -96,40 +96,21 @@ impl Difficulty<'_> {
/// ///
/// [`try_mode`]: Self::try_mode /// [`try_mode`]: Self::try_mode
pub fn mode_or_ignore(&mut self, mode: GameMode) -> &mut Self { pub fn mode_or_ignore(&mut self, mode: GameMode) -> &mut Self {
let map = match mode { let map = self.map.as_ref();
GameMode::Osu => {
let Some(converted) = OsuBeatmap::try_from_ref(self.map.as_ref()) else {
return self;
};
converted.map let map_opt = match mode {
} GameMode::Osu => OsuBeatmap::try_from_ref(map).map(Converted::into_inner),
GameMode::Taiko => { GameMode::Taiko => TaikoBeatmap::try_from_ref(map).map(Converted::into_inner),
let Some(converted) = TaikoBeatmap::try_from_ref(self.map.as_ref()) else { GameMode::Catch => CatchBeatmap::try_from_ref(map).map(Converted::into_inner),
return self; GameMode::Mania => ManiaBeatmap::try_from_ref(map).map(Converted::into_inner),
};
converted.map
}
GameMode::Catch => {
let Some(converted) = CatchBeatmap::try_from_ref(self.map.as_ref()) else {
return self;
};
converted.map
}
GameMode::Mania => {
let Some(converted) = ManiaBeatmap::try_from_ref(self.map.as_ref()) else {
return self;
};
converted.map
}
}; };
if matches!(map, Cow::Owned(_)) { match map_opt {
let map = map.into_owned(); Some(cow @ Cow::Owned(_)) => {
self.map = Cow::Owned(map); let map = cow.into_owned();
self.map = Cow::Owned(map);
}
Some(Cow::Borrowed(_)) | None => {}
} }
self self
+1 -1
View File
@@ -68,7 +68,7 @@ pub fn convert_objects(
let mut last_pos = None; let mut last_pos = None;
let mut last_start_time = 0.0; let mut last_start_time = 0.0;
for h in converted.map.hit_objects.iter() { for h in converted.hit_objects.iter() {
let mut new_objects = convert_object(h, converted, count, &mut bufs); let mut new_objects = convert_object(h, converted, count, &mut bufs);
apply_pos_offset( apply_pos_offset(
+1 -1
View File
@@ -53,7 +53,7 @@ impl CatchDifficultySetup {
let attrs = CatchDifficultyAttributes { let attrs = CatchDifficultyAttributes {
ar: map_attrs.ar, ar: map_attrs.ar,
is_convert: converted.map.is_convert, is_convert: converted.is_convert,
..Default::default() ..Default::default()
}; };
+2 -4
View File
@@ -28,16 +28,14 @@ impl<'a> JuiceStream<'a> {
count: &mut ObjectCountBuilder, count: &mut ObjectCountBuilder,
bufs: &'a mut JuiceStreamBufs, bufs: &'a mut JuiceStreamBufs,
) -> Self { ) -> Self {
let slider_multiplier = converted.map.slider_multiplier; let slider_multiplier = converted.slider_multiplier;
let slider_tick_rate = converted.map.slider_tick_rate; let slider_tick_rate = converted.slider_tick_rate;
let beat_len = converted let beat_len = converted
.map
.timing_point_at(start_time) .timing_point_at(start_time)
.map_or(TimingPoint::DEFAULT_BEAT_LEN, |point| point.beat_len); .map_or(TimingPoint::DEFAULT_BEAT_LEN, |point| point.beat_len);
let slider_velocity = converted let slider_velocity = converted
.map
.difficulty_point_at(start_time) .difficulty_point_at(start_time)
.map_or(DifficultyPoint::DEFAULT_SLIDER_VELOCITY, |point| { .map_or(DifficultyPoint::DEFAULT_SLIDER_VELOCITY, |point| {
point.slider_velocity point.slider_velocity
+1 -1
View File
@@ -225,7 +225,7 @@ mod tests {
.unwrap() .unwrap()
.unchecked_into_converted::<Mania>(); .unchecked_into_converted::<Mania>();
let map = converted.map; let map = &converted;
assert!(map.is_convert); assert!(map.is_convert);
assert_eq!(map.mode, GameMode::Mania); assert_eq!(map.mode, GameMode::Mania);
+5 -7
View File
@@ -64,9 +64,9 @@ impl ManiaGradualDifficulty {
pub fn new(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self { pub fn new(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self {
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
let mods = difficulty.get_mods(); let mods = difficulty.get_mods();
let total_columns = converted.map.cs.round_even().max(1.0); let total_columns = converted.cs.round_even().max(1.0);
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
let mut params = ObjectParams::new(converted.map.as_ref()); let mut params = ObjectParams::new(&converted);
let HitWindows { od: hit_window, .. } = converted let HitWindows { od: hit_window, .. } = converted
.attributes() .attributes()
@@ -75,7 +75,6 @@ impl ManiaGradualDifficulty {
.hit_windows(); .hit_windows();
let mania_objects = converted let mania_objects = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.map(|h| ManiaObject::new(h, total_columns, &mut params)) .map(|h| ManiaObject::new(h, total_columns, &mut params))
@@ -88,13 +87,12 @@ impl ManiaGradualDifficulty {
let mut curr_combo = 0; let mut curr_combo = 0;
let objects_is_circle: Box<[_]> = converted let objects_is_circle: Box<[_]> = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.map(HitObject::is_circle) .map(HitObject::is_circle)
.collect(); .collect();
if let Some(h) = converted.map.hit_objects.first() { if let Some(h) = converted.hit_objects.first() {
let hit_object = ManiaObject::new(h, total_columns, &mut params); let hit_object = ManiaObject::new(h, total_columns, &mut params);
increment_combo_raw( increment_combo_raw(
@@ -110,7 +108,7 @@ impl ManiaGradualDifficulty {
mods, mods,
clock_rate, clock_rate,
objects_is_circle, objects_is_circle,
is_convert: converted.map.is_convert, is_convert: converted.is_convert,
strain, strain,
diff_objects, diff_objects,
hit_window, hit_window,
@@ -239,7 +237,7 @@ mod tests {
let mut gradual_2nd = ManiaGradualDifficulty::new(&difficulty, &converted); let mut gradual_2nd = ManiaGradualDifficulty::new(&difficulty, &converted);
let mut gradual_3rd = ManiaGradualDifficulty::new(&difficulty, &converted); let mut gradual_3rd = ManiaGradualDifficulty::new(&difficulty, &converted);
let hit_objects_len = converted.map.hit_objects.len(); let hit_objects_len = converted.hit_objects.len();
for i in 1.. { for i in 1.. {
let Some(next_gradual) = gradual.next() else { let Some(next_gradual) = gradual.next() else {
+4 -8
View File
@@ -21,10 +21,7 @@ pub fn difficulty(
difficulty: &ModeDifficulty, difficulty: &ModeDifficulty,
converted: &ManiaBeatmap<'_>, converted: &ManiaBeatmap<'_>,
) -> ManiaDifficultyAttributes { ) -> ManiaDifficultyAttributes {
let n_objects = cmp::min( let n_objects = cmp::min(difficulty.get_passed_objects(), converted.hit_objects.len()) as u32;
difficulty.get_passed_objects(),
converted.map.hit_objects.len(),
) as u32;
let values = DifficultyValues::calculate(difficulty, converted); let values = DifficultyValues::calculate(difficulty, converted);
@@ -40,7 +37,7 @@ pub fn difficulty(
hit_window, hit_window,
max_combo: values.max_combo, max_combo: values.max_combo,
n_objects, n_objects,
is_convert: converted.map.is_convert, is_convert: converted.is_convert,
} }
} }
@@ -52,12 +49,11 @@ pub struct DifficultyValues {
impl DifficultyValues { impl DifficultyValues {
pub fn calculate(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self { pub fn calculate(difficulty: &ModeDifficulty, converted: &ManiaBeatmap<'_>) -> Self {
let take = difficulty.get_passed_objects(); let take = difficulty.get_passed_objects();
let total_columns = converted.map.cs.round_even().max(1.0); let total_columns = converted.cs.round_even().max(1.0);
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
let mut params = ObjectParams::new(converted.map.as_ref()); let mut params = ObjectParams::new(&converted);
let mania_objects = converted let mania_objects = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.map(|h| ManiaObject::new(h, total_columns, &mut params)) .map(|h| ManiaObject::new(h, total_columns, &mut params))
+1 -1
View File
@@ -137,7 +137,7 @@ mod tests {
let mut state = ManiaScoreState::default(); let mut state = ManiaScoreState::default();
let hit_objects_len = converted.map.hit_objects.len(); let hit_objects_len = converted.hit_objects.len();
for i in 1.. { for i in 1.. {
state.misses += 1; state.misses += 1;
+1 -1
View File
@@ -938,7 +938,7 @@ mod tests {
let attrs = ModeDifficulty::new().calculate(&converted); let attrs = ModeDifficulty::new().calculate(&converted);
assert_eq!(N_OBJECTS, converted.map.hit_objects.len() as u32); assert_eq!(N_OBJECTS, converted.hit_objects.len() as u32);
attrs attrs
}) })
+1 -1
View File
@@ -239,7 +239,7 @@ impl From<&Beatmap> for BeatmapAttributesBuilder {
impl<M> From<&Converted<'_, M>> for BeatmapAttributesBuilder { impl<M> From<&Converted<'_, M>> for BeatmapAttributesBuilder {
fn from(converted: &Converted<'_, M>) -> Self { fn from(converted: &Converted<'_, M>) -> Self {
Self::new(converted.map.as_ref()) Self::new(&converted)
} }
} }
+14 -18
View File
@@ -3,6 +3,7 @@ use std::{
borrow::Cow, borrow::Cow,
fmt::{Debug, Formatter, Result as FmtResult}, fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData, marker::PhantomData,
ops::Deref,
}; };
use crate::{ use crate::{
@@ -10,7 +11,7 @@ use crate::{
ModeDifficulty, ModeDifficulty,
}; };
use super::{attributes::BeatmapAttributesBuilder, Beatmap}; use super::Beatmap;
const INCOMPATIBLE_MODES: &str = "the gamemodes were incompatible"; const INCOMPATIBLE_MODES: &str = "the gamemodes were incompatible";
@@ -29,7 +30,7 @@ const INCOMPATIBLE_MODES: &str = "the gamemodes were incompatible";
/// ///
/// All other conversions are incompatible. /// All other conversions are incompatible.
pub struct Converted<'a, M> { pub struct Converted<'a, M> {
pub(crate) map: Cow<'a, Beatmap>, map: Cow<'a, Beatmap>,
mode: PhantomData<M>, mode: PhantomData<M>,
} }
@@ -42,23 +43,10 @@ impl<'a, M> Converted<'a, M> {
mode: PhantomData, mode: PhantomData,
} }
} }
}
impl<M> Converted<'_, M> { /// Returns the internal [`Beatmap`].
/// Sum up the duration of all breaks (in milliseconds). pub fn into_inner(self) -> Cow<'a, Beatmap> {
pub fn total_break_time(&self) -> f64 { self.map
self.map.total_break_time()
}
/// Returns a [`BeatmapAttributesBuilder`] to calculate modified beatmap
/// attributes.
pub fn attributes(&self) -> BeatmapAttributesBuilder {
self.into()
}
/// The beats per minute of the map.
pub fn bpm(&self) -> f64 {
self.map.bpm()
} }
} }
@@ -212,3 +200,11 @@ impl<M> PartialEq for Converted<'_, M> {
self.map == other.map self.map == other.map
} }
} }
impl<M> Deref for Converted<'_, M> {
type Target = Beatmap;
fn deref(&self) -> &Self::Target {
self.map.as_ref()
}
}
+2 -3
View File
@@ -40,7 +40,6 @@ pub fn convert_objects(
let mut ticks_buf = Vec::new(); let mut ticks_buf = Vec::new();
let mut osu_objects: Box<[_]> = converted let mut osu_objects: Box<[_]> = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.map(|h| OsuObject::new(h, converted, &mut curve_bufs, &mut ticks_buf)) .map(|h| OsuObject::new(h, converted, &mut curve_bufs, &mut ticks_buf))
@@ -71,9 +70,9 @@ pub fn convert_objects(
osu_objects.iter_mut().for_each(OsuObject::finalize_tail); osu_objects.iter_mut().for_each(OsuObject::finalize_tail);
} }
let stack_threshold = time_preempt * f64::from(converted.map.stack_leniency); let stack_threshold = time_preempt * f64::from(converted.stack_leniency);
if converted.map.version >= 6 { if converted.version >= 6 {
stacking(&mut osu_objects, stack_threshold); stacking(&mut osu_objects, stack_threshold);
} else { } else {
old_stacking(&mut osu_objects, stack_threshold); old_stacking(&mut osu_objects, stack_threshold);
+2 -2
View File
@@ -89,7 +89,7 @@ impl OsuGradualDifficulty {
&scaling_factor, &scaling_factor,
mods.hr(), mods.hr(),
time_preempt, time_preempt,
converted.map.hit_objects.len(), converted.hit_objects.len(),
&mut attrs, &mut attrs,
); );
@@ -290,7 +290,7 @@ mod tests {
let mut gradual_2nd = OsuGradualDifficulty::new(&difficulty, &converted); let mut gradual_2nd = OsuGradualDifficulty::new(&difficulty, &converted);
let mut gradual_3rd = OsuGradualDifficulty::new(&difficulty, &converted); let mut gradual_3rd = OsuGradualDifficulty::new(&difficulty, &converted);
let hit_objects_len = converted.map.hit_objects.len(); let hit_objects_len = converted.hit_objects.len();
for i in 1.. { for i in 1.. {
let Some(next_gradual) = gradual.next() else { let Some(next_gradual) = gradual.next() else {
+1 -2
View File
@@ -140,8 +140,7 @@ impl DifficultyValues {
let mut flashlight = Skill::new(&mut skills.flashlight, &diff_objects); let mut flashlight = Skill::new(&mut skills.flashlight, &diff_objects);
// The first hit object has no difficulty object // The first hit object has no difficulty object
let take_diff_objects = let take_diff_objects = cmp::min(converted.hit_objects.len(), take).saturating_sub(1);
cmp::min(converted.map.hit_objects.len(), take).saturating_sub(1);
for hit_object in diff_objects.iter().take(take_diff_objects) { for hit_object in diff_objects.iter().take(take_diff_objects) {
aim.process(hit_object); aim.process(hit_object);
+10 -12
View File
@@ -167,22 +167,20 @@ impl OsuSlider {
ticks_buf: &mut Vec<SliderEvent>, ticks_buf: &mut Vec<SliderEvent>,
) -> Self { ) -> Self {
let start_time = h.start_time; let start_time = h.start_time;
let slider_multiplier = converted.map.slider_multiplier; let slider_multiplier = converted.slider_multiplier;
let slider_tick_rate = converted.map.slider_tick_rate; let slider_tick_rate = converted.slider_tick_rate;
let beat_len = converted let beat_len = converted
.map
.timing_point_at(start_time) .timing_point_at(start_time)
.map_or(TimingPoint::DEFAULT_BEAT_LEN, |point| point.beat_len); .map_or(TimingPoint::DEFAULT_BEAT_LEN, |point| point.beat_len);
let (slider_velocity, generate_ticks) = let (slider_velocity, generate_ticks) = converted.difficulty_point_at(start_time).map_or(
converted.map.difficulty_point_at(start_time).map_or( (
( DifficultyPoint::DEFAULT_SLIDER_VELOCITY,
DifficultyPoint::DEFAULT_SLIDER_VELOCITY, DifficultyPoint::DEFAULT_GENERATE_TICKS,
DifficultyPoint::DEFAULT_GENERATE_TICKS, ),
), |point| (point.slider_velocity, point.generate_ticks),
|point| (point.slider_velocity, point.generate_ticks), );
);
let path = slider.curve(curve_bufs); let path = slider.curve(curve_bufs);
@@ -197,7 +195,7 @@ impl OsuSlider {
let duration = end_time - start_time; let duration = end_time - start_time;
let span_duration = duration / span_count; let span_duration = duration / span_count;
let tick_dist_multiplier = if converted.map.version < 8 { let tick_dist_multiplier = if converted.version < 8 {
slider_velocity.recip() slider_velocity.recip()
} else { } else {
1.0 1.0
+1 -1
View File
@@ -147,7 +147,7 @@ mod tests {
let mut state = OsuScoreState::default(); let mut state = OsuScoreState::default();
let hit_objects_len = converted.map.hit_objects.len(); let hit_objects_len = converted.hit_objects.len();
for i in 1.. { for i in 1.. {
state.misses += 1; state.misses += 1;
+4 -6
View File
@@ -75,8 +75,8 @@ impl TaikoGradualDifficulty {
let clock_rate = difficulty.get_clock_rate(); let clock_rate = difficulty.get_clock_rate();
let first_combos = match ( let first_combos = match (
converted.map.hit_objects.first().map(HitObject::is_circle), converted.hit_objects.first().map(HitObject::is_circle),
converted.map.hit_objects.get(1).map(HitObject::is_circle), converted.hit_objects.get(1).map(HitObject::is_circle),
) { ) {
(None, _) | (Some(false), Some(false) | None) => FirstTwoCombos::None, (None, _) | (Some(false), Some(false) | None) => FirstTwoCombos::None,
(Some(true), Some(false) | None) => FirstTwoCombos::OnlyFirst, (Some(true), Some(false) | None) => FirstTwoCombos::OnlyFirst,
@@ -105,12 +105,11 @@ impl TaikoGradualDifficulty {
let attrs = TaikoDifficultyAttributes { let attrs = TaikoDifficultyAttributes {
hit_window, hit_window,
is_convert: converted.map.is_convert, is_convert: converted.is_convert,
..Default::default() ..Default::default()
}; };
let total_hits = converted let total_hits = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.filter(|h| h.is_circle()) .filter(|h| h.is_circle())
@@ -288,10 +287,9 @@ mod tests {
let mut gradual_2nd = TaikoGradualDifficulty::new(&difficulty, &converted); let mut gradual_2nd = TaikoGradualDifficulty::new(&difficulty, &converted);
let mut gradual_3rd = TaikoGradualDifficulty::new(&difficulty, &converted); let mut gradual_3rd = TaikoGradualDifficulty::new(&difficulty, &converted);
let hit_objects_len = converted.map.hit_objects.len(); let hit_objects_len = converted.hit_objects.len();
let n_hits = converted let n_hits = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.filter(|h| h.is_circle()) .filter(|h| h.is_circle())
+3 -4
View File
@@ -40,7 +40,7 @@ pub fn difficulty(
let mut attrs = TaikoDifficultyAttributes { let mut attrs = TaikoDifficultyAttributes {
hit_window, hit_window,
max_combo, max_combo,
is_convert: converted.map.is_convert, is_convert: converted.is_convert,
..Default::default() ..Default::default()
}; };
@@ -146,10 +146,9 @@ impl DifficultyValues {
n_diff_objects: &mut usize, n_diff_objects: &mut usize,
) -> TaikoDifficultyObjects { ) -> TaikoDifficultyObjects {
let mut hit_objects_iter = converted let mut hit_objects_iter = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.zip(converted.map.hit_sounds.iter()) .zip(converted.hit_sounds.iter())
.map(|(h, s)| TaikoObject::new(h, *s)) .map(|(h, s)| TaikoObject::new(h, *s))
.inspect(|h| { .inspect(|h| {
if *max_combo < take { if *max_combo < take {
@@ -164,7 +163,7 @@ impl DifficultyValues {
}; };
let mut diff_objects = let mut diff_objects =
TaikoDifficultyObjects::with_capacity(converted.map.hit_objects.len() - 2); TaikoDifficultyObjects::with_capacity(converted.hit_objects.len() - 2);
for (i, curr) in hit_objects_iter.enumerate() { for (i, curr) in hit_objects_iter.enumerate() {
let diff_object = TaikoDifficultyObject::new( let diff_object = TaikoDifficultyObject::new(
+1 -2
View File
@@ -143,10 +143,9 @@ mod tests {
let mut state = TaikoScoreState::default(); let mut state = TaikoScoreState::default();
let hit_objects_len = converted.map.hit_objects.len(); let hit_objects_len = converted.hit_objects.len();
let n_hits = converted let n_hits = converted
.map
.hit_objects .hit_objects
.iter() .iter()
.filter(|h| h.is_circle()) .filter(|h| h.is_circle())
-1
View File
@@ -316,7 +316,6 @@ impl<'map> TryFrom<OsuPerformance<'map>> for TaikoPerformance<'map> {
/// was called. /// was called.
/// ///
/// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes /// [`OsuDifficultyAttributes`]: crate::osu::OsuDifficultyAttributes
fn try_from(mut osu: OsuPerformance<'map>) -> Result<Self, Self::Error> { fn try_from(mut osu: OsuPerformance<'map>) -> Result<Self, Self::Error> {
let MapOrAttrs::Map(converted) = osu.map_or_attrs else { let MapOrAttrs::Map(converted) = osu.map_or_attrs else {
return Err(osu); return Err(osu);