From d15f8c2f3a1ffb79fb1fcfd2e0ee2717b2c0cbb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 17:11:14 +0900 Subject: [PATCH 1/5] Fix beatmaps with multiple `osb` files potentially reading the storyboard from the wrong one In stable, the storyboard filename is fixed. In lazer, we were always looking for the first `.osb` in the database. In the case a beatmap archive housed more than one `.osb` files, this may load the incorrect one. Using `GetDisplayString` here feels like it could potentially go wrong in the future, so I'm open to hard-coding this locally (or using string manipulation to remove the ` [creator_name]` portion of the beatmap's filename). Open to opinions on that. Fixes storyboard playback in https://osu.ppy.sh/beatmapsets/1913687#osu/3947758 --- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index e6f96330e7..546f0e6c3a 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -20,6 +20,7 @@ using osu.Framework.Statistics; using osu.Framework.Testing; using osu.Game.Beatmaps.Formats; using osu.Game.Database; +using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Storyboards; @@ -268,7 +269,7 @@ namespace osu.Game.Beatmaps Stream storyboardFileStream = null; - if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename is string storyboardFilename) + if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.Equals($"{BeatmapSetInfo.GetDisplayString()}.osb", StringComparison.OrdinalIgnoreCase))?.Filename is string storyboardFilename) { string storyboardFileStorePath = BeatmapSetInfo?.GetPathForFile(storyboardFilename); storyboardFileStream = GetStream(storyboardFileStorePath); From 78cfe2f5476ec361f46f93c6376ba46188273093 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 18:46:52 +0900 Subject: [PATCH 2/5] Fix hit circle kiai test scene not always working as expected --- .../TestSceneHitCircleKiai.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs index 2c9f1acd2c..718664d649 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs @@ -4,29 +4,38 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public partial class TestSceneHitCircleKiai : TestSceneHitCircle + public partial class TestSceneHitCircleKiai : TestSceneHitCircle, IBeatSyncProvider { + private ControlPointInfo controlPoints { get; set; } + [SetUp] public void SetUp() => Schedule(() => { - var controlPointInfo = new ControlPointInfo(); + controlPoints = new ControlPointInfo(); - controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); - controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + controlPoints.Add(0, new TimingControlPoint { BeatLength = 500 }); + controlPoints.Add(0, new EffectControlPoint { KiaiMode = true }); Beatmap.Value = CreateWorkingBeatmap(new Beatmap { - ControlPointInfo = controlPointInfo + ControlPointInfo = controlPoints }); // track needs to be playing for BeatSyncedContainer to work. Beatmap.Value.Track.Start(); }); + + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => new ChannelAmplitudes(); + ControlPointInfo IBeatSyncProvider.ControlPoints => controlPoints; + IClock IBeatSyncProvider.Clock => Clock; } } From 48d68b0f4f385ca862db266011cb9fffcb5efee7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 18:59:26 +0900 Subject: [PATCH 3/5] Add very basic kiai flash to argon hit circles --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index db458ec48a..d50a3eba13 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -43,6 +43,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); private readonly FlashPiece flash; + private readonly KiaiFlash kiaiFlash; [Resolved] private DrawableHitObject drawableObject { get; set; } = null!; @@ -82,6 +83,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Anchor = Anchor.Centre, Origin = Anchor.Centre, }, + new CircularContainer + { + Masking = true, + Size = Size, + Child = kiaiFlash = new KiaiFlash + { + RelativeSizeAxes = Axes.Both, + } + }, number = new OsuSpriteText { Font = OsuFont.Default.With(size: 52, weight: FontWeight.Bold), @@ -117,6 +127,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon outerGradient.ClearTransforms(targetMember: nameof(Colour)); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); + kiaiFlash.Colour = colour.NewValue; outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; From 7cc4fd4efc9fce06a9705152234bd12c7657c3c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 15:09:36 +0900 Subject: [PATCH 4/5] Use the exact method stable uses for generating storyboard filenames --- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 33 ++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index 546f0e6c3a..76a31a6f78 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -20,7 +20,6 @@ using osu.Framework.Statistics; using osu.Framework.Testing; using osu.Game.Beatmaps.Formats; using osu.Game.Database; -using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Storyboards; @@ -269,7 +268,10 @@ namespace osu.Game.Beatmaps Stream storyboardFileStream = null; - if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.Equals($"{BeatmapSetInfo.GetDisplayString()}.osb", StringComparison.OrdinalIgnoreCase))?.Filename is string storyboardFilename) + string mainStoryboardFilename = getMainStoryboardFilename(BeatmapSetInfo.Metadata); + + if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.Equals(mainStoryboardFilename, StringComparison.OrdinalIgnoreCase))?.Filename is string + storyboardFilename) { string storyboardFileStorePath = BeatmapSetInfo?.GetPathForFile(storyboardFilename); storyboardFileStream = GetStream(storyboardFileStorePath); @@ -313,6 +315,33 @@ namespace osu.Game.Beatmaps } public override Stream GetStream(string storagePath) => resources.Files.GetStream(storagePath); + + private string getMainStoryboardFilename(IBeatmapMetadataInfo metadata) + { + // Matches stable implementation, because it's probably simpler than trying to do anything else. + // This may need to be reconsidered after we begin storing storyboards in the new editor. + return windowsFilenameStrip( + (metadata.Artist.Length > 0 ? metadata.Artist + @" - " + metadata.Title : Path.GetFileNameWithoutExtension(metadata.AudioFile)) + + (metadata.Author.Username.Length > 0 ? @" (" + metadata.Author.Username + @")" : string.Empty) + + @".osb"); + + string windowsFilenameStrip(string entry) + { + // Inlined from Path.GetInvalidFilenameChars() to ensure the windows characters are used (to match stable). + char[] invalidCharacters = + { + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12', + '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', + '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' + }; + + foreach (char c in invalidCharacters) + entry = entry.Replace(c.ToString(), string.Empty); + + return entry; + } + } } } } From de1d473d2908527a903f12fed42713b359aac81a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 15:24:10 +0900 Subject: [PATCH 5/5] Fix kiai flash being visible and incorrectly sized during hit animation --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 04a4d4bede..e7e6e26b5e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); private readonly FlashPiece flash; - private readonly KiaiFlash kiaiFlash; + private readonly Container kiaiContainer; private Bindable configHitLighting = null!; @@ -83,11 +83,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new CircularContainer + kiaiContainer = new CircularContainer { Masking = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Size = Size, - Child = kiaiFlash = new KiaiFlash + Child = new KiaiFlash { RelativeSizeAxes = Axes.Both, } @@ -129,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon outerGradient.ClearTransforms(targetMember: nameof(Colour)); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); - kiaiFlash.Colour = colour.NewValue; + kiaiContainer.Colour = colour.NewValue; outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; @@ -191,6 +193,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // gradient layers. border.ResizeTo(Size * shrink_size + new Vector2(border.BorderThickness), resize_duration, Easing.OutElasticHalf); + // Kiai flash should track the overall size but also be cleaned up quite fast, so we don't get additional + // flashes after the hit animation is already in a mostly-completed state. + kiaiContainer.ResizeTo(Size * shrink_size, resize_duration, Easing.OutElasticHalf); + kiaiContainer.FadeOut(flash_in_duration, Easing.OutQuint); + // The outer gradient is resize with a slight delay from the border. // This is to give it a bomb-like effect, with the border "triggering" its animation when getting close. using (BeginDelayedSequence(flash_in_duration / 12))