From 19a0eaade9b48f65bbf51ebbac98ba32b98b9dba Mon Sep 17 00:00:00 2001 From: Sebastian Krajewski Date: Thu, 6 Aug 2020 04:41:44 +0200 Subject: [PATCH 01/11] Allow storyboard sprites to load textures from skins --- .../Drawables/DrawableStoryboardSprite.cs | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index d8d3248659..d40af903a6 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Skinning; namespace osu.Game.Storyboards.Drawables { @@ -17,6 +18,12 @@ namespace osu.Game.Storyboards.Drawables { public StoryboardSprite Sprite { get; } + private ISkinSource currentSkin; + + private TextureStore storyboardTextureStore; + + private string texturePath; + private bool flipH; public bool FlipH @@ -114,14 +121,36 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(IBindable beatmap, TextureStore textureStore) + private void load(ISkinSource skin, IBindable beatmap, TextureStore textureStore) { - var path = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - if (path == null) - return; + if (skin != null) + { + currentSkin = skin; + skin.SourceChanged += onChange; + } + + storyboardTextureStore = textureStore; + + texturePath = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + + skinChanged(); - Texture = textureStore.Get(path); Sprite.ApplyTransforms(this); } + + private void onChange() => + // schedule required to avoid calls after disposed. + // note that this has the side-effect of components only performing a possible texture change when they are alive. + Scheduler.AddOnce(skinChanged); + + private void skinChanged() + { + var newTexture = currentSkin?.GetTexture(Sprite.Path) ?? storyboardTextureStore?.Get(texturePath); + + if (Texture == newTexture) return; + + Size = Vector2.Zero; // Sprite size needs to be recalculated (e.g. aspect ratio of combo number textures may differ between skins) + Texture = newTexture; + } } } From e0ae2b3ebf20e1454af64b001e81365e301f221b Mon Sep 17 00:00:00 2001 From: Sebastian Krajewski Date: Thu, 6 Aug 2020 17:07:36 +0200 Subject: [PATCH 02/11] Switch to SkinReloadableDrawable --- .../Drawables/DrawableStoryboardSprite.cs | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index d40af903a6..d4f27bf4aa 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -14,11 +14,11 @@ using osu.Game.Skinning; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardSprite : Sprite, IFlippable, IVectorScalable + public class DrawableStoryboardSprite : SkinReloadableDrawable, IFlippable, IVectorScalable { public StoryboardSprite Sprite { get; } - private ISkinSource currentSkin; + private Sprite drawableSprite; private TextureStore storyboardTextureStore; @@ -123,34 +123,28 @@ namespace osu.Game.Storyboards.Drawables [BackgroundDependencyLoader] private void load(ISkinSource skin, IBindable beatmap, TextureStore textureStore) { - if (skin != null) + InternalChild = drawableSprite = new Sprite { - currentSkin = skin; - skin.SourceChanged += onChange; - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }; storyboardTextureStore = textureStore; texturePath = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - skinChanged(); - Sprite.ApplyTransforms(this); } - private void onChange() => - // schedule required to avoid calls after disposed. - // note that this has the side-effect of components only performing a possible texture change when they are alive. - Scheduler.AddOnce(skinChanged); - - private void skinChanged() + protected override void SkinChanged(ISkinSource skin, bool allowFallback) { - var newTexture = currentSkin?.GetTexture(Sprite.Path) ?? storyboardTextureStore?.Get(texturePath); + base.SkinChanged(skin, allowFallback); + var newTexture = skin?.GetTexture(Sprite.Path) ?? storyboardTextureStore?.Get(texturePath); - if (Texture == newTexture) return; + if (drawableSprite.Texture == newTexture) return; - Size = Vector2.Zero; // Sprite size needs to be recalculated (e.g. aspect ratio of combo number textures may differ between skins) - Texture = newTexture; + drawableSprite.Size = Vector2.Zero; // Sprite size needs to be recalculated (e.g. aspect ratio of combo number textures may differ between skins) + drawableSprite.Texture = newTexture; } } } From 7cf225520fdfb93bffc18fc84eed087aa29d7cea Mon Sep 17 00:00:00 2001 From: Sebastian Krajewski Date: Sat, 8 Aug 2020 02:43:39 +0200 Subject: [PATCH 03/11] Change from BDL to Resolved --- osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index d4f27bf4aa..45c74da892 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -20,7 +20,8 @@ namespace osu.Game.Storyboards.Drawables private Sprite drawableSprite; - private TextureStore storyboardTextureStore; + [Resolved] + private TextureStore storyboardTextureStore { get; set; } private string texturePath; @@ -121,7 +122,7 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IBindable beatmap, TextureStore textureStore) + private void load(IBindable beatmap) { InternalChild = drawableSprite = new Sprite { @@ -129,8 +130,6 @@ namespace osu.Game.Storyboards.Drawables Origin = Anchor.Centre }; - storyboardTextureStore = textureStore; - texturePath = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; Sprite.ApplyTransforms(this); From cf76d777623d32947d1285384c71f540a586dea3 Mon Sep 17 00:00:00 2001 From: Sebastian Krajewski Date: Fri, 9 Oct 2020 17:34:01 +0200 Subject: [PATCH 04/11] Fix osu!classic skin elements not showing up in storyboards --- osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 45c74da892..cd09cafbce 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.IO; using osuTK; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -138,7 +139,8 @@ namespace osu.Game.Storyboards.Drawables protected override void SkinChanged(ISkinSource skin, bool allowFallback) { base.SkinChanged(skin, allowFallback); - var newTexture = skin?.GetTexture(Sprite.Path) ?? storyboardTextureStore?.Get(texturePath); + + var newTexture = skin?.GetTexture(Path.GetFileNameWithoutExtension(Sprite.Path)) ?? storyboardTextureStore?.Get(texturePath); if (drawableSprite.Texture == newTexture) return; From f41fc71e42c9301889a8cff230a723a8ba8007d8 Mon Sep 17 00:00:00 2001 From: Sebastian Krajewski Date: Fri, 9 Oct 2020 18:02:21 +0200 Subject: [PATCH 05/11] Allow storyboard animations to load textures from skins --- .../Drawables/DrawableStoryboardAnimation.cs | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 72e52f6106..963cf37fea 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.IO; using osuTK; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -10,13 +12,22 @@ using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Skinning; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardAnimation : TextureAnimation, IFlippable, IVectorScalable + public class DrawableStoryboardAnimation : SkinReloadableDrawable, IFlippable, IVectorScalable { public StoryboardAnimation Animation { get; } + private TextureAnimation drawableTextureAnimation; + + [Resolved] + private TextureStore storyboardTextureStore { get; set; } + + private readonly List texturePathsRaw = new List(); + private readonly List texturePaths = new List(); + private bool flipH; public bool FlipH @@ -108,28 +119,48 @@ namespace osu.Game.Storyboards.Drawables Animation = animation; Origin = animation.Origin; Position = animation.InitialPosition; - Loop = animation.LoopType == AnimationLoopType.LoopForever; LifetimeStart = animation.StartTime; LifetimeEnd = animation.EndTime; } [BackgroundDependencyLoader] - private void load(IBindable beatmap, TextureStore textureStore) + private void load(IBindable beatmap) { + InternalChild = drawableTextureAnimation = new TextureAnimation + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Loop = Animation.LoopType == AnimationLoopType.LoopForever + }; + for (var frame = 0; frame < Animation.FrameCount; frame++) { var framePath = Animation.Path.Replace(".", frame + "."); + texturePathsRaw.Add(Path.GetFileNameWithoutExtension(framePath)); var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - if (path == null) - continue; - - var texture = textureStore.Get(path); - AddFrame(texture, Animation.FrameDelay); + texturePaths.Add(path); } Animation.ApplyTransforms(this); } + + protected override void SkinChanged(ISkinSource skin, bool allowFallback) + { + base.SkinChanged(skin, allowFallback); + + drawableTextureAnimation.ClearFrames(); + + for (var frame = 0; frame < Animation.FrameCount; frame++) + { + var texture = skin?.GetTexture(texturePathsRaw[frame]) ?? storyboardTextureStore?.Get(texturePaths[frame]); + + if (texture == null) + continue; + + drawableTextureAnimation.AddFrame(texture, Animation.FrameDelay); + } + } } } From e54836a63e4051bc517d1d044cfe566490fabf33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Oct 2020 22:27:59 +0200 Subject: [PATCH 06/11] Use SkinnableSprite to avoid unnecessary reloads --- .../Drawables/DrawableStoryboardAnimation.cs | 52 +++++-------------- .../Drawables/DrawableStoryboardSprite.cs | 39 ++++---------- 2 files changed, 24 insertions(+), 67 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 963cf37fea..c3b6dde44b 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -2,13 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; -using System.IO; using osuTK; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; +using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -16,18 +15,10 @@ using osu.Game.Skinning; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardAnimation : SkinReloadableDrawable, IFlippable, IVectorScalable + public class DrawableStoryboardAnimation : DrawableAnimation, IFlippable, IVectorScalable { public StoryboardAnimation Animation { get; } - private TextureAnimation drawableTextureAnimation; - - [Resolved] - private TextureStore storyboardTextureStore { get; set; } - - private readonly List texturePathsRaw = new List(); - private readonly List texturePaths = new List(); - private bool flipH; public bool FlipH @@ -119,48 +110,31 @@ namespace osu.Game.Storyboards.Drawables Animation = animation; Origin = animation.Origin; Position = animation.InitialPosition; + Loop = animation.LoopType == AnimationLoopType.LoopForever; LifetimeStart = animation.StartTime; LifetimeEnd = animation.EndTime; } [BackgroundDependencyLoader] - private void load(IBindable beatmap) + private void load(IBindable beatmap, TextureStore textureStore) { - InternalChild = drawableTextureAnimation = new TextureAnimation - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Loop = Animation.LoopType == AnimationLoopType.LoopForever - }; - for (var frame = 0; frame < Animation.FrameCount; frame++) { var framePath = Animation.Path.Replace(".", frame + "."); - texturePathsRaw.Add(Path.GetFileNameWithoutExtension(framePath)); - var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - texturePaths.Add(path); + var storyboardPath = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + var frameSprite = storyboardPath != null + ? (Drawable)new Sprite + { + Texture = textureStore.Get(storyboardPath) + } + : new SkinnableSprite(framePath); // fall back to skin textures if not found in storyboard files. + + AddFrame(frameSprite, Animation.FrameDelay); } Animation.ApplyTransforms(this); } - - protected override void SkinChanged(ISkinSource skin, bool allowFallback) - { - base.SkinChanged(skin, allowFallback); - - drawableTextureAnimation.ClearFrames(); - - for (var frame = 0; frame < Animation.FrameCount; frame++) - { - var texture = skin?.GetTexture(texturePathsRaw[frame]) ?? storyboardTextureStore?.Get(texturePaths[frame]); - - if (texture == null) - continue; - - drawableTextureAnimation.AddFrame(texture, Animation.FrameDelay); - } - } } } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index cd09cafbce..95774de898 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.IO; using osuTK; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; @@ -15,17 +15,10 @@ using osu.Game.Skinning; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardSprite : SkinReloadableDrawable, IFlippable, IVectorScalable + public class DrawableStoryboardSprite : CompositeDrawable, IFlippable, IVectorScalable { public StoryboardSprite Sprite { get; } - private Sprite drawableSprite; - - [Resolved] - private TextureStore storyboardTextureStore { get; set; } - - private string texturePath; - private bool flipH; public bool FlipH @@ -123,29 +116,19 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(IBindable beatmap) + private void load(IBindable beatmap, TextureStore textureStore) { - InternalChild = drawableSprite = new Sprite - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }; + var storyboardPath = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + var sprite = storyboardPath != null + ? (Drawable)new Sprite + { + Texture = textureStore.Get(storyboardPath) + } + : new SkinnableSprite(Sprite.Path); // fall back to skin textures if not found in storyboard files. - texturePath = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + InternalChild = sprite.With(s => s.Anchor = s.Origin = Anchor.Centre); Sprite.ApplyTransforms(this); } - - protected override void SkinChanged(ISkinSource skin, bool allowFallback) - { - base.SkinChanged(skin, allowFallback); - - var newTexture = skin?.GetTexture(Path.GetFileNameWithoutExtension(Sprite.Path)) ?? storyboardTextureStore?.Get(texturePath); - - if (drawableSprite.Texture == newTexture) return; - - drawableSprite.Size = Vector2.Zero; // Sprite size needs to be recalculated (e.g. aspect ratio of combo number textures may differ between skins) - drawableSprite.Texture = newTexture; - } } } From cdd56ece871a9999288196a859033a44665a3c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Oct 2020 23:32:04 +0200 Subject: [PATCH 07/11] Read UseSkinSprites when decoding storyboards --- .../Beatmaps/Formats/LegacyStoryboardDecoder.cs | 16 ++++++++++++++++ osu.Game/Storyboards/Storyboard.cs | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 269449ef80..e2550d1ca4 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -48,6 +48,10 @@ namespace osu.Game.Beatmaps.Formats switch (section) { + case Section.General: + handleGeneral(storyboard, line); + return; + case Section.Events: handleEvents(line); return; @@ -60,6 +64,18 @@ namespace osu.Game.Beatmaps.Formats base.ParseLine(storyboard, section, line); } + private void handleGeneral(Storyboard storyboard, string line) + { + var pair = SplitKeyVal(line); + + switch (pair.Key) + { + case "UseSkinSprites": + storyboard.UseSkinSprites = pair.Value == "1"; + break; + } + } + private void handleEvents(string line) { var depth = 0; diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index b0fb583d62..daafdf015d 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -15,6 +15,11 @@ namespace osu.Game.Storyboards public BeatmapInfo BeatmapInfo = new BeatmapInfo(); + /// + /// Whether the storyboard can fall back to skin sprites in case no matching storyboard sprites are found. + /// + public bool UseSkinSprites { get; set; } + public bool HasDrawable => Layers.Any(l => l.Elements.Any(e => e.IsDrawable)); public double FirstEventTime => Layers.Min(l => l.Elements.FirstOrDefault()?.StartTime ?? 0); From 58a54c5b6c71c01315dd5effeb33f08a61449db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Oct 2020 23:40:20 +0200 Subject: [PATCH 08/11] Utilise UseSkinSprites value in storyboard sprite logic --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 1 + .../Drawables/DrawableStoryboardAnimation.cs | 11 ++++------- .../Storyboards/Drawables/DrawableStoryboardSprite.cs | 11 ++++------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index ec461fa095..4bc28e6cef 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -15,6 +15,7 @@ namespace osu.Game.Storyboards.Drawables { public class DrawableStoryboard : Container { + [Cached] public Storyboard Storyboard { get; } protected override Container Content { get; } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index c3b6dde44b..8382f91d1f 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -117,19 +117,16 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(IBindable beatmap, TextureStore textureStore) + private void load(IBindable beatmap, TextureStore textureStore, Storyboard storyboard) { for (var frame = 0; frame < Animation.FrameCount; frame++) { var framePath = Animation.Path.Replace(".", frame + "."); var storyboardPath = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - var frameSprite = storyboardPath != null - ? (Drawable)new Sprite - { - Texture = textureStore.Get(storyboardPath) - } - : new SkinnableSprite(framePath); // fall back to skin textures if not found in storyboard files. + var frameSprite = storyboard.UseSkinSprites && storyboardPath == null + ? (Drawable)new SkinnableSprite(framePath) + : new Sprite { Texture = textureStore.Get(storyboardPath) }; AddFrame(frameSprite, Animation.FrameDelay); } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 95774de898..9599375c76 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -116,15 +116,12 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(IBindable beatmap, TextureStore textureStore) + private void load(IBindable beatmap, TextureStore textureStore, Storyboard storyboard) { var storyboardPath = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - var sprite = storyboardPath != null - ? (Drawable)new Sprite - { - Texture = textureStore.Get(storyboardPath) - } - : new SkinnableSprite(Sprite.Path); // fall back to skin textures if not found in storyboard files. + var sprite = storyboard.UseSkinSprites && storyboardPath == null + ? (Drawable)new SkinnableSprite(Sprite.Path) + : new Sprite { Texture = textureStore.Get(storyboardPath) }; InternalChild = sprite.With(s => s.Anchor = s.Origin = Anchor.Centre); From 8c14c9e1c4eb36789b150d14e273e6b6ccf1f772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 20 Oct 2020 22:42:47 +0200 Subject: [PATCH 09/11] Add basic test coverage --- .../TestSceneDrawableStoryboardSprite.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs new file mode 100644 index 0000000000..9501026edc --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -0,0 +1,65 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Skinning; +using osu.Game.Storyboards; +using osu.Game.Storyboards.Drawables; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneDrawableStoryboardSprite : SkinnableTestScene + { + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [Cached] + private Storyboard storyboard { get; set; } = new Storyboard(); + + [Test] + public void TestSkinSpriteDisallowedByDefault() + { + const string lookup_name = "hitcircleoverlay"; + + AddStep("allow skin lookup", () => storyboard.UseSkinSprites = false); + + AddStep("create sprites", () => SetContents( + () => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); + + assertSpritesFromSkin(false); + } + + [Test] + public void TestAllowLookupFromSkin() + { + const string lookup_name = "hitcircleoverlay"; + + AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); + + AddStep("create sprites", () => SetContents( + () => createSprite(lookup_name, Anchor.Centre, Vector2.Zero))); + + assertSpritesFromSkin(true); + } + + private DrawableStoryboardSprite createSprite(string lookupName, Anchor origin, Vector2 initialPosition) + => new DrawableStoryboardSprite( + new StoryboardSprite(lookupName, origin, initialPosition) + ).With(s => + { + s.LifetimeStart = double.MinValue; + s.LifetimeEnd = double.MaxValue; + }); + + private void assertSpritesFromSkin(bool fromSkin) => + AddAssert($"sprites are {(fromSkin ? "from skin" : "from storyboard")}", + () => this.ChildrenOfType() + .All(sprite => sprite.ChildrenOfType().Any() == fromSkin)); + } +} From 1b84402b966744babc95e20790f83fa3061b9f8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Oct 2020 15:33:38 +0900 Subject: [PATCH 10/11] Centralise and share logic for storyboard frame lookup method --- .../Drawables/DrawableStoryboardAnimation.cs | 19 +++++-------------- .../Drawables/DrawableStoryboardSprite.cs | 16 +++++----------- osu.Game/Storyboards/Storyboard.cs | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 8382f91d1f..97de239e4a 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -2,16 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osuTK; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Skinning; +using osuTK; namespace osu.Game.Storyboards.Drawables { @@ -117,18 +113,13 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(IBindable beatmap, TextureStore textureStore, Storyboard storyboard) + private void load(TextureStore textureStore, Storyboard storyboard) { - for (var frame = 0; frame < Animation.FrameCount; frame++) + for (int frame = 0; frame < Animation.FrameCount; frame++) { - var framePath = Animation.Path.Replace(".", frame + "."); + string framePath = Animation.Path.Replace(".", frame + "."); - var storyboardPath = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - var frameSprite = storyboard.UseSkinSprites && storyboardPath == null - ? (Drawable)new SkinnableSprite(framePath) - : new Sprite { Texture = textureStore.Get(storyboardPath) }; - - AddFrame(frameSprite, Animation.FrameDelay); + AddFrame(storyboard.CreateSpriteFromResourcePath(framePath, textureStore), Animation.FrameDelay); } Animation.ApplyTransforms(this); diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 9599375c76..1adbe688e7 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -2,16 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osuTK; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Skinning; +using osuTK; namespace osu.Game.Storyboards.Drawables { @@ -116,14 +112,12 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(IBindable beatmap, TextureStore textureStore, Storyboard storyboard) + private void load(TextureStore textureStore, Storyboard storyboard) { - var storyboardPath = beatmap.Value.BeatmapSetInfo?.Files?.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; - var sprite = storyboard.UseSkinSprites && storyboardPath == null - ? (Drawable)new SkinnableSprite(Sprite.Path) - : new Sprite { Texture = textureStore.Get(storyboardPath) }; + var drawable = storyboard.CreateSpriteFromResourcePath(Sprite.Path, textureStore); - InternalChild = sprite.With(s => s.Anchor = s.Origin = Anchor.Centre); + if (drawable != null) + InternalChild = drawable.With(s => s.Anchor = s.Origin = Anchor.Centre); Sprite.ApplyTransforms(this); } diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index daafdf015d..e0d18eab00 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -1,9 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; +using osu.Game.Skinning; using osu.Game.Storyboards.Drawables; namespace osu.Game.Storyboards @@ -69,5 +74,19 @@ namespace osu.Game.Storyboards drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); return drawable; } + + public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore) + { + Drawable drawable = null; + var storyboardPath = BeatmapInfo.BeatmapSet?.Files?.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath; + + if (storyboardPath != null) + drawable = new Sprite { Texture = textureStore.Get(storyboardPath) }; + // if the texture isn't available locally in the beatmap, some storyboards choose to source from the underlying skin lookup hierarchy. + else if (UseSkinSprites) + drawable = new SkinnableSprite(path); + + return drawable; + } } } From 4f746792fba1f427357675b0c054ff84b2bd95b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Oct 2020 15:46:24 +0900 Subject: [PATCH 11/11] Fix regression causing storyboard sprites to have incorrect origin support --- osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 1adbe688e7..7b1a6d54da 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -109,6 +109,8 @@ namespace osu.Game.Storyboards.Drawables LifetimeStart = sprite.StartTime; LifetimeEnd = sprite.EndTime; + + AutoSizeAxes = Axes.Both; } [BackgroundDependencyLoader] @@ -117,7 +119,7 @@ namespace osu.Game.Storyboards.Drawables var drawable = storyboard.CreateSpriteFromResourcePath(Sprite.Path, textureStore); if (drawable != null) - InternalChild = drawable.With(s => s.Anchor = s.Origin = Anchor.Centre); + InternalChild = drawable; Sprite.ApplyTransforms(this); }