From a23de0b1885a3c5f62e4b9971b094167d8c5b1a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Feb 2025 16:29:39 +0900 Subject: [PATCH 1/2] Avoid accessing `WorkingBeatmap.Beatmap` every update call Notice in passing. Comes with overheads that can be easily avoided. Left a note for a future (slightly more involved) optimisation. --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 ++ .../Play/MasterGameplayClockContainer.cs | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 890a969415..fd40097c4e 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -203,6 +203,8 @@ namespace osu.Game.Beatmaps { try { + // TODO: This is a touch expensive and can become an issue if being accessed every Update call. + // Optimally we would not involve the async flow if things are already loaded. return loadBeatmapAsync().GetResultSafely(); } catch (AggregateException ae) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index c20d461526..747ea3090c 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Play private readonly Bindable playbackRateValid = new Bindable(true); - private readonly WorkingBeatmap beatmap; + private readonly IBeatmap beatmap; private Track track; @@ -63,20 +63,19 @@ namespace osu.Game.Screens.Play /// /// Create a new master gameplay clock container. /// - /// The beatmap to be used for time and metadata references. + /// The beatmap to be used for time and metadata references. /// The latest time which should be used when introducing gameplay. Will be used when skipping forward. - public MasterGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStartTime) - : base(beatmap.Track, applyOffsets: true, requireDecoupling: true) + public MasterGameplayClockContainer(WorkingBeatmap working, double gameplayStartTime) + : base(working.Track, applyOffsets: true, requireDecoupling: true) { - this.beatmap = beatmap; - - track = beatmap.Track; + beatmap = working.Beatmap; + track = working.Track; GameplayStartTime = gameplayStartTime; - StartTime = findEarliestStartTime(gameplayStartTime, beatmap); + StartTime = findEarliestStartTime(gameplayStartTime, working); } - private static double findEarliestStartTime(double gameplayStartTime, WorkingBeatmap beatmap) + private static double findEarliestStartTime(double gameplayStartTime, WorkingBeatmap working) { // here we are trying to find the time to start playback from the "zero" point. // generally this is either zero, or some point earlier than zero in the case of storyboards, lead-ins etc. @@ -86,15 +85,15 @@ namespace osu.Game.Screens.Play // if a storyboard is present, it may dictate the appropriate start time by having events in negative time space. // this is commonly used to display an intro before the audio track start. - double? firstStoryboardEvent = beatmap.Storyboard.EarliestEventTime; + double? firstStoryboardEvent = working.Storyboard.EarliestEventTime; if (firstStoryboardEvent != null) time = Math.Min(time, firstStoryboardEvent.Value); // some beatmaps specify a current lead-in time which should be used instead of the ruleset-provided value when available. // this is not available as an option in the live editor but can still be applied via .osu editing. - double firstHitObjectTime = beatmap.Beatmap.HitObjects.First().StartTime; - if (beatmap.Beatmap.AudioLeadIn > 0) - time = Math.Min(time, firstHitObjectTime - beatmap.Beatmap.AudioLeadIn); + double firstHitObjectTime = working.Beatmap.HitObjects.First().StartTime; + if (working.Beatmap.AudioLeadIn > 0) + time = Math.Min(time, firstHitObjectTime - working.Beatmap.AudioLeadIn); return time; } @@ -136,7 +135,7 @@ namespace osu.Game.Screens.Play { removeAdjustmentsFromTrack(); - track = new TrackVirtual(beatmap.Track.Length); + track = new TrackVirtual(track.Length); track.Seek(CurrentTime); if (IsRunning) track.Start(); @@ -228,9 +227,8 @@ namespace osu.Game.Screens.Play removeAdjustmentsFromTrack(); } - ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo; + ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.ControlPointInfo; + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => track.CurrentAmplitudes; IClock IBeatSyncProvider.Clock => this; - - ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; } } From 99192404f125b3f5f380b4a167f7a6be1d6646ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Feb 2025 19:26:14 +0900 Subject: [PATCH 2/2] Tidy up `WorkingBeatmap` passing in `ctor` --- .../Screens/Play/MasterGameplayClockContainer.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 747ea3090c..07ecb5a5fb 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -12,6 +12,7 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Overlays; +using osu.Game.Storyboards; namespace osu.Game.Screens.Play { @@ -72,10 +73,10 @@ namespace osu.Game.Screens.Play track = working.Track; GameplayStartTime = gameplayStartTime; - StartTime = findEarliestStartTime(gameplayStartTime, working); + StartTime = findEarliestStartTime(gameplayStartTime, beatmap, working.Storyboard); } - private static double findEarliestStartTime(double gameplayStartTime, WorkingBeatmap working) + private static double findEarliestStartTime(double gameplayStartTime, IBeatmap beatmap, Storyboard storyboard) { // here we are trying to find the time to start playback from the "zero" point. // generally this is either zero, or some point earlier than zero in the case of storyboards, lead-ins etc. @@ -85,15 +86,15 @@ namespace osu.Game.Screens.Play // if a storyboard is present, it may dictate the appropriate start time by having events in negative time space. // this is commonly used to display an intro before the audio track start. - double? firstStoryboardEvent = working.Storyboard.EarliestEventTime; + double? firstStoryboardEvent = storyboard.EarliestEventTime; if (firstStoryboardEvent != null) time = Math.Min(time, firstStoryboardEvent.Value); // some beatmaps specify a current lead-in time which should be used instead of the ruleset-provided value when available. // this is not available as an option in the live editor but can still be applied via .osu editing. - double firstHitObjectTime = working.Beatmap.HitObjects.First().StartTime; - if (working.Beatmap.AudioLeadIn > 0) - time = Math.Min(time, firstHitObjectTime - working.Beatmap.AudioLeadIn); + double firstHitObjectTime = beatmap.HitObjects.First().StartTime; + if (beatmap.AudioLeadIn > 0) + time = Math.Min(time, firstHitObjectTime - beatmap.AudioLeadIn); return time; }