diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index e674e7512c..6931cea81e 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -1,22 +1,23 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; -using osuTK; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play; +using osuTK; namespace osu.Game.Storyboards.Drawables { @@ -57,12 +58,18 @@ namespace osu.Game.Storyboards.Drawables [Cached(typeof(IReadOnlyList))] public IReadOnlyList Mods { get; } - private DependencyContainer dependencies; + [Resolved] + private GameHost host { get; set; } = null!; + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + private DependencyContainer dependencies = null!; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - public DrawableStoryboard(Storyboard storyboard, IReadOnlyList mods = null) + public DrawableStoryboard(Storyboard storyboard, IReadOnlyList? mods = null) { Storyboard = storyboard; Mods = mods ?? Array.Empty(); @@ -85,12 +92,15 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader(true)] - private void load(IGameplayClock clock, CancellationToken? cancellationToken, GameHost host, RealmAccess realm) + private void load(IGameplayClock? clock, CancellationToken? cancellationToken) { if (clock != null) Clock = clock; - dependencies.Cache(new TextureStore(host.Renderer, host.CreateTextureLoaderStore(new RealmFileStore(realm, host.Storage).Store), false, scaleAdjust: 1)); + dependencies.CacheAs(typeof(TextureStore), + new TextureStore(host.Renderer, host.CreateTextureLoaderStore( + CreateResourceLookupStore() + ), false, scaleAdjust: 1)); foreach (var layer in Storyboard.Layers) { @@ -102,6 +112,8 @@ namespace osu.Game.Storyboards.Drawables lastEventEndTime = Storyboard.LatestEventTime; } + protected virtual IResourceStore CreateResourceLookupStore() => new StoryboardResourceLookupStore(Storyboard, realm, host); + protected override void Update() { base.Update(); @@ -115,5 +127,32 @@ namespace osu.Game.Storyboards.Drawables foreach (var layer in Children) layer.Enabled = passing ? layer.Layer.VisibleWhenPassing : layer.Layer.VisibleWhenFailing; } + + private class StoryboardResourceLookupStore : IResourceStore + { + private readonly IResourceStore realmFileStore; + private readonly Storyboard storyboard; + + public StoryboardResourceLookupStore(Storyboard storyboard, RealmAccess realm, GameHost host) + { + realmFileStore = new RealmFileStore(realm, host.Storage).Store; + this.storyboard = storyboard; + } + + public void Dispose() => + realmFileStore.Dispose(); + + public byte[] Get(string name) => + realmFileStore.Get(storyboard.GetStoragePathFromStoryboardPath(name)); + + public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) => + realmFileStore.GetAsync(storyboard.GetStoragePathFromStoryboardPath(name), cancellationToken); + + public Stream GetStream(string name) => + realmFileStore.GetStream(storyboard.GetStoragePathFromStoryboardPath(name)); + + public IEnumerable GetAvailableResources() => + realmFileStore.GetAvailableResources(); + } } } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 82c01ea6a1..054a50456b 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -99,15 +99,13 @@ namespace osu.Game.Storyboards.Drawables { int frameIndex = 0; - Texture frameTexture = storyboard.GetTextureFromPath(getFramePath(frameIndex), textureStore); + Texture frameTexture = textureStore.Get(getFramePath(frameIndex)); if (frameTexture != null) { // sourcing from storyboard. for (frameIndex = 0; frameIndex < Animation.FrameCount; frameIndex++) - { - AddFrame(storyboard.GetTextureFromPath(getFramePath(frameIndex), textureStore), Animation.FrameDelay); - } + AddFrame(textureStore.Get(getFramePath(frameIndex)), Animation.FrameDelay); } else if (storyboard.UseSkinSprites) { diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index ec0cb7ca19..379de1a497 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -90,7 +90,7 @@ namespace osu.Game.Storyboards.Drawables [BackgroundDependencyLoader] private void load(TextureStore textureStore, Storyboard storyboard) { - Texture = storyboard.GetTextureFromPath(Sprite.Path, textureStore); + Texture = textureStore.Get(Sprite.Path); if (Texture == null && storyboard.UseSkinSprites) { diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 566e064aad..1892855d3d 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Storyboards.Drawables; @@ -92,7 +91,7 @@ namespace osu.Game.Storyboards private static readonly string[] image_extensions = { @".png", @".jpg" }; - public Texture? GetTextureFromPath(string path, TextureStore textureStore) + public virtual string? GetStoragePathFromStoryboardPath(string path) { string? resolvedPath = null; @@ -102,10 +101,7 @@ namespace osu.Game.Storyboards } else { - // Just doing this extension logic locally here for simplicity. - // - // A more "sane" path may be to use the ISkinSource.GetTexture path (which will use the extensions of the underlying TextureStore), - // but comes with potential complexity (what happens if the user has beatmap skins disabled?). + // Some old storyboards don't include a file extension, so let's best guess at one. foreach (string ext in image_extensions) { if ((resolvedPath = BeatmapInfo.BeatmapSet?.GetPathForFile($"{path}{ext}")) != null) @@ -113,10 +109,7 @@ namespace osu.Game.Storyboards } } - if (!string.IsNullOrEmpty(resolvedPath)) - return textureStore.Get(resolvedPath); - - return null; + return resolvedPath; } } }