Make Beatmaps parsable as skins

This commit is contained in:
Dean Herbert 2018-03-14 20:45:04 +09:00
parent 553fd3b789
commit dbcf755618
7 changed files with 105 additions and 12 deletions

View File

@ -10,6 +10,7 @@
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 @@ protected override Storyboard GetStoryboard()
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;
}
}
}
}

View File

@ -14,6 +14,7 @@
using System.IO;
using osu.Game.IO.Serialization;
using System.Diagnostics;
using osu.Game.Skinning;
namespace osu.Game.Beatmaps
{
@ -40,6 +41,7 @@ protected WorkingBeatmap(BeatmapInfo beatmapInfo)
track = new AsyncLazy<Track>(populateTrack);
waveform = new AsyncLazy<Waveform>(populateWaveform);
storyboard = new AsyncLazy<Storyboard>(populateStoryboard);
skin = new AsyncLazy<Skin>(populateSkin);
}
/// <summary>
@ -56,6 +58,7 @@ public void Save()
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 @@ private Track populateTrack()
private Storyboard populateStoryboard() => GetStoryboard();
public bool SkinLoaded => skin.IsResultAvailable;
public Skin Skin => skin.Value.Result;
public async Task<Skin> GetSkinAsync() => await skin.Value;
private readonly AsyncLazy<Skin> skin;
private Skin populateSkin() => GetSkin();
public void TransferTo(WorkingBeatmap other)
{
if (track.IsResultAvailable && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo))
@ -123,6 +133,7 @@ public virtual void Dispose()
if (BackgroundLoaded) Background?.Dispose();
if (WaveformLoaded) Waveform?.Dispose();
if (StoryboardLoaded) Storyboard?.Dispose();
if (SkinLoaded) Skin?.Dispose();
}
/// <summary>

View File

@ -10,6 +10,8 @@ namespace osu.Game.Database
/// </summary>
/// <typeparam name="TFile">The model representing a file.</typeparam>
public interface IHasFiles<TFile>
where TFile : INamedFileInfo
{
List<TFile> Files { get; set; }
}

View File

@ -0,0 +1,31 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// 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<byte[]> storage)
: base(new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() })
{
storage = new LegacySkinResourceStore<BeatmapSetFileInfo>(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);
}
}
}
}

View File

@ -10,24 +10,24 @@
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<byte[]> storage, AudioManager audioManager)
: base(skin)
: this(skin)
{
storage = new LegacySkinResourceStore(skin, storage);
storage = new LegacySkinResourceStore<SkinFileInfo>(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 @@ public LegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager au
Configuration = new SkinConfiguration();
}
protected LegacySkin(SkinInfo skin) : base(skin)
{
}
public override Drawable GetDrawableComponent(string componentName)
{
switch (componentName)
@ -53,7 +57,7 @@ public override Drawable GetDrawableComponent(string componentName)
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 @@ public override Drawable GetDrawableComponent(string componentName)
public override SampleChannel GetSample(string sampleName) => samples.Get(sampleName);
private class LegacySkinResourceStore : IResourceStore<byte[]>
protected class LegacySkinResourceStore<T> : IResourceStore<byte[]>
where T : INamedFileInfo
{
private readonly SkinInfo skin;
private readonly IHasFiles<T> source;
private readonly IResourceStore<byte[]> underlyingStore;
private string getPathForFile(string filename)
@ -72,14 +77,14 @@ private string getPathForFile(string filename)
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<byte[]> underlyingStore)
public LegacySkinResourceStore(IHasFiles<T> source, IResourceStore<byte[]> underlyingStore)
{
this.skin = skin;
this.source = source;
this.underlyingStore = underlyingStore;
}

View File

@ -1,12 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// 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 @@ protected Skin(SkinInfo skin)
{
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
}
}

View File

@ -871,6 +871,7 @@
<Compile Include="Screens\Tournament\Teams\DrawingsTeam.cs" />
<Compile Include="Screens\Tournament\Teams\ITeamList.cs" />
<Compile Include="Screens\Tournament\Teams\StorageBackedTeamList.cs" />
<Compile Include="Skinning\BeatmapSkin.cs" />
<Compile Include="Skinning\DefaultSkin.cs" />
<Compile Include="Skinning\LegacySkin.cs" />
<Compile Include="Skinning\LegacySkinDecoder.cs" />