From dbcf755618fc2cd425b66f7ae784b652749f1bae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Mar 2018 20:45:04 +0900 Subject: [PATCH] Make Beatmaps parsable as skins --- .../Beatmaps/BeatmapManager_WorkingBeatmap.cs | 18 +++++++++++ osu.Game/Beatmaps/WorkingBeatmap.cs | 11 +++++++ osu.Game/Database/IHasFiles.cs | 2 ++ osu.Game/Skinning/BeatmapSkin.cs | 31 +++++++++++++++++++ osu.Game/Skinning/LegacySkin.cs | 27 +++++++++------- osu.Game/Skinning/Skin.cs | 27 +++++++++++++++- osu.Game/osu.Game.csproj | 1 + 7 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 osu.Game/Skinning/BeatmapSkin.cs diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index fb11684309..d7d17c980c 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -10,6 +10,7 @@ using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Game.Beatmaps.Formats; using osu.Game.Graphics.Textures; +using osu.Game.Skinning; using osu.Game.Storyboards; namespace osu.Game.Beatmaps @@ -100,6 +101,23 @@ namespace osu.Game.Beatmaps return storyboard; } + + protected override Skin GetSkin() + { + Skin skin; + try + { + // todo: this needs an AudioManager + skin = new BeatmapSkin(BeatmapInfo, store); + } + catch (Exception e) + { + Logger.Error(e, "Skin failed to load"); + skin = new DefaultSkin(); + } + + return skin; + } } } } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 8a2a7b01a1..5c0ad7685b 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -14,6 +14,7 @@ using osu.Framework.IO.File; using System.IO; using osu.Game.IO.Serialization; using System.Diagnostics; +using osu.Game.Skinning; namespace osu.Game.Beatmaps { @@ -40,6 +41,7 @@ namespace osu.Game.Beatmaps track = new AsyncLazy(populateTrack); waveform = new AsyncLazy(populateWaveform); storyboard = new AsyncLazy(populateStoryboard); + skin = new AsyncLazy(populateSkin); } /// @@ -56,6 +58,7 @@ namespace osu.Game.Beatmaps protected abstract Beatmap GetBeatmap(); protected abstract Texture GetBackground(); protected abstract Track GetTrack(); + protected virtual Skin GetSkin() => new DefaultSkin(); protected virtual Waveform GetWaveform() => new Waveform(); protected virtual Storyboard GetStoryboard() => new Storyboard { BeatmapInfo = BeatmapInfo }; @@ -109,6 +112,13 @@ namespace osu.Game.Beatmaps private Storyboard populateStoryboard() => GetStoryboard(); + public bool SkinLoaded => skin.IsResultAvailable; + public Skin Skin => skin.Value.Result; + public async Task GetSkinAsync() => await skin.Value; + private readonly AsyncLazy skin; + + private Skin populateSkin() => GetSkin(); + public void TransferTo(WorkingBeatmap other) { if (track.IsResultAvailable && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) @@ -123,6 +133,7 @@ namespace osu.Game.Beatmaps if (BackgroundLoaded) Background?.Dispose(); if (WaveformLoaded) Waveform?.Dispose(); if (StoryboardLoaded) Storyboard?.Dispose(); + if (SkinLoaded) Skin?.Dispose(); } /// diff --git a/osu.Game/Database/IHasFiles.cs b/osu.Game/Database/IHasFiles.cs index deaf75360c..faf3f16dfe 100644 --- a/osu.Game/Database/IHasFiles.cs +++ b/osu.Game/Database/IHasFiles.cs @@ -10,6 +10,8 @@ namespace osu.Game.Database /// /// The model representing a file. public interface IHasFiles + where TFile : INamedFileInfo + { List Files { get; set; } } diff --git a/osu.Game/Skinning/BeatmapSkin.cs b/osu.Game/Skinning/BeatmapSkin.cs new file mode 100644 index 0000000000..beab2a42d7 --- /dev/null +++ b/osu.Game/Skinning/BeatmapSkin.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.IO; +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; +using osu.Game.Beatmaps; + +namespace osu.Game.Skinning +{ + public class BeatmapSkin : LegacySkin + { + public BeatmapSkin(BeatmapInfo beatmap, IResourceStore storage) + : base(new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() }) + { + storage = new LegacySkinResourceStore(beatmap.BeatmapSet, storage); + + // todo: sample support + // samples = audioManager.GetSampleManager(storage); + + Textures = new TextureStore(new RawTextureLoaderStore(storage)); + + var decoder = new LegacySkinDecoder(); + + using (StreamReader reader = new StreamReader(storage.GetStream(beatmap.Path))) + { + Configuration = decoder.Decode(reader); + } + } + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index b531d791b0..bae0d5c997 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -10,24 +10,24 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Game.Database; namespace osu.Game.Skinning { public class LegacySkin : Skin { - private readonly TextureStore textures; + protected TextureStore Textures; private readonly SampleManager samples; public LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager) - : base(skin) + : this(skin) { - storage = new LegacySkinResourceStore(skin, storage); + storage = new LegacySkinResourceStore(skin, storage); samples = audioManager.GetSampleManager(storage); - textures = new TextureStore(new RawTextureLoaderStore(storage)); + Textures = new TextureStore(new RawTextureLoaderStore(storage)); Stream stream = storage.GetStream("skin.ini"); - if (stream != null) using (StreamReader reader = new StreamReader(stream)) Configuration = new LegacySkinDecoder().Decode(reader); @@ -35,6 +35,10 @@ namespace osu.Game.Skinning Configuration = new SkinConfiguration(); } + protected LegacySkin(SkinInfo skin) : base(skin) + { + } + public override Drawable GetDrawableComponent(string componentName) { switch (componentName) @@ -53,7 +57,7 @@ namespace osu.Game.Skinning break; } - var texture = textures.Get(componentName); + var texture = Textures.Get(componentName); if (texture == null) return null; return new Sprite { Texture = texture }; @@ -61,9 +65,10 @@ namespace osu.Game.Skinning public override SampleChannel GetSample(string sampleName) => samples.Get(sampleName); - private class LegacySkinResourceStore : IResourceStore + protected class LegacySkinResourceStore : IResourceStore + where T : INamedFileInfo { - private readonly SkinInfo skin; + private readonly IHasFiles source; private readonly IResourceStore underlyingStore; private string getPathForFile(string filename) @@ -72,14 +77,14 @@ namespace osu.Game.Skinning string lastPiece = filename.Split('/').Last(); - var file = skin.Files.FirstOrDefault(f => + var file = source.Files.FirstOrDefault(f => string.Equals(hasExtension ? f.Filename : Path.GetFileNameWithoutExtension(f.Filename), lastPiece, StringComparison.InvariantCultureIgnoreCase)); return file?.FileInfo.StoragePath; } - public LegacySkinResourceStore(SkinInfo skin, IResourceStore underlyingStore) + public LegacySkinResourceStore(IHasFiles source, IResourceStore underlyingStore) { - this.skin = skin; + this.source = source; this.underlyingStore = underlyingStore; } diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 7b4e894dfd..53bcf30b0e 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -1,12 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; namespace osu.Game.Skinning { - public abstract class Skin + public abstract class Skin : IDisposable { public readonly SkinInfo SkinInfo; @@ -20,5 +21,29 @@ namespace osu.Game.Skinning { SkinInfo = skin; } + + #region Disposal + + ~Skin() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private bool isDisposed; + + protected virtual void Dispose(bool isDisposing) + { + if (isDisposed) + return; + isDisposed = true; + } + + #endregion } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b325e52ed1..50c272e827 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -871,6 +871,7 @@ +