mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 08:52:55 +08:00
Merge pull request #13441 from frenzibyte/ruleset-resources-skin
Provide access to ruleset resources during `ISkinSource` lookups
This commit is contained in:
commit
094cd31361
@ -2,14 +2,15 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -18,14 +19,21 @@ using osu.Game.Tests.Visual;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Rulesets
|
namespace osu.Game.Tests.Rulesets
|
||||||
{
|
{
|
||||||
|
[HeadlessTest]
|
||||||
public class TestSceneRulesetSkinProvidingContainer : OsuTestScene
|
public class TestSceneRulesetSkinProvidingContainer : OsuTestScene
|
||||||
{
|
{
|
||||||
private SkinRequester requester;
|
private SkinRequester requester;
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new TestSceneRulesetDependencies.TestRuleset();
|
protected override Ruleset CreateRuleset() => new TestSceneRulesetDependencies.TestRuleset();
|
||||||
|
|
||||||
[Cached(typeof(ISkinSource))]
|
[Test]
|
||||||
private readonly ISkinSource testSource = new TestSkinProvider();
|
public void TestRulesetResources()
|
||||||
|
{
|
||||||
|
setupProviderStep();
|
||||||
|
|
||||||
|
AddAssert("ruleset texture retrieved via skin", () => requester.GetTexture("test-image") != null);
|
||||||
|
AddAssert("ruleset sample retrieved via skin", () => requester.GetSample(new SampleInfo("test-sample")) != null);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestEarlyAddedSkinRequester()
|
public void TestEarlyAddedSkinRequester()
|
||||||
@ -38,7 +46,7 @@ namespace osu.Game.Tests.Rulesets
|
|||||||
|
|
||||||
rulesetSkinProvider.Add(requester = new SkinRequester());
|
rulesetSkinProvider.Add(requester = new SkinRequester());
|
||||||
|
|
||||||
requester.OnLoadAsync += () => textureOnLoad = requester.GetTexture(TestSkinProvider.TEXTURE_NAME);
|
requester.OnLoadAsync += () => textureOnLoad = requester.GetTexture("test-image");
|
||||||
|
|
||||||
Child = rulesetSkinProvider;
|
Child = rulesetSkinProvider;
|
||||||
});
|
});
|
||||||
@ -46,6 +54,15 @@ namespace osu.Game.Tests.Rulesets
|
|||||||
AddAssert("requester got correct initial texture", () => textureOnLoad != null);
|
AddAssert("requester got correct initial texture", () => textureOnLoad != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupProviderStep()
|
||||||
|
{
|
||||||
|
AddStep("setup provider", () =>
|
||||||
|
{
|
||||||
|
Child = new RulesetSkinProvidingContainer(Ruleset.Value.CreateInstance(), Beatmap.Value.Beatmap, Beatmap.Value.Skin)
|
||||||
|
.WithChild(requester = new SkinRequester());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private class SkinRequester : Drawable, ISkin
|
private class SkinRequester : Drawable, ISkin
|
||||||
{
|
{
|
||||||
private ISkinSource skin;
|
private ISkinSource skin;
|
||||||
@ -68,28 +85,5 @@ namespace osu.Game.Tests.Rulesets
|
|||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestSkinProvider : ISkinSource
|
|
||||||
{
|
|
||||||
public const string TEXTURE_NAME = "some-texture";
|
|
||||||
|
|
||||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotImplementedException();
|
|
||||||
|
|
||||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => componentName == TEXTURE_NAME ? Texture.WhitePixel : null;
|
|
||||||
|
|
||||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
|
||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
|
||||||
|
|
||||||
public event Action SourceChanged
|
|
||||||
{
|
|
||||||
add { }
|
|
||||||
remove { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => lookupFunction(this) ? this : null;
|
|
||||||
|
|
||||||
public IEnumerable<ISkin> AllSources => new[] { this };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
osu.Game/Skinning/ResourceStoreBackedSkin.cs
Normal file
57
osu.Game/Skinning/ResourceStoreBackedSkin.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
|
||||||
|
namespace osu.Game.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="ISkin"/> that uses an underlying <see cref="IResourceStore{T}"/> with namespaces for resources retrieval.
|
||||||
|
/// </summary>
|
||||||
|
public class ResourceStoreBackedSkin : ISkin, IDisposable
|
||||||
|
{
|
||||||
|
private readonly TextureStore textures;
|
||||||
|
private readonly ISampleStore samples;
|
||||||
|
|
||||||
|
public ResourceStoreBackedSkin(IResourceStore<byte[]> resources, GameHost host, AudioManager audio)
|
||||||
|
{
|
||||||
|
textures = new TextureStore(host.CreateTextureLoaderStore(new NamespacedResourceStore<byte[]>(resources, @"Textures")));
|
||||||
|
samples = audio.GetSampleStore(new NamespacedResourceStore<byte[]>(resources, @"Samples"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable? GetDrawableComponent(ISkinComponent component) => null;
|
||||||
|
|
||||||
|
public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => textures.Get(componentName, wrapModeS, wrapModeT);
|
||||||
|
|
||||||
|
public ISample? GetSample(ISampleInfo sampleInfo)
|
||||||
|
{
|
||||||
|
foreach (var lookup in sampleInfo.LookupNames)
|
||||||
|
{
|
||||||
|
ISample? sample = samples.Get(lookup);
|
||||||
|
if (sample != null)
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup) => null;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
textures.Dispose();
|
||||||
|
samples.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,14 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
@ -44,11 +48,16 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
private ISkinSource parentSource;
|
private ISkinSource parentSource;
|
||||||
|
|
||||||
|
private ResourceStoreBackedSkin rulesetResourcesSkin;
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
{
|
{
|
||||||
parentSource = parent.Get<ISkinSource>();
|
parentSource = parent.Get<ISkinSource>();
|
||||||
parentSource.SourceChanged += OnSourceChanged;
|
parentSource.SourceChanged += OnSourceChanged;
|
||||||
|
|
||||||
|
if (Ruleset.CreateResourceStore() is IResourceStore<byte[]> resources)
|
||||||
|
rulesetResourcesSkin = new ResourceStoreBackedSkin(resources, parent.Get<GameHost>(), parent.Get<AudioManager>());
|
||||||
|
|
||||||
// ensure sources are populated and ready for use before childrens' asynchronous load flow.
|
// ensure sources are populated and ready for use before childrens' asynchronous load flow.
|
||||||
UpdateSkinSources();
|
UpdateSkinSources();
|
||||||
|
|
||||||
@ -78,6 +87,16 @@ namespace osu.Game.Skinning
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lastDefaultSkinIndex = SkinSources.IndexOf(SkinSources.OfType<DefaultSkin>().LastOrDefault());
|
||||||
|
|
||||||
|
// Ruleset resources should be given the ability to override game-wide defaults
|
||||||
|
// This is achieved by placing them before the last instance of DefaultSkin.
|
||||||
|
// Note that DefaultSkin may not be present in some test scenes.
|
||||||
|
if (lastDefaultSkinIndex >= 0)
|
||||||
|
SkinSources.Insert(lastDefaultSkinIndex, rulesetResourcesSkin);
|
||||||
|
else
|
||||||
|
SkinSources.Add(rulesetResourcesSkin);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ISkin GetLegacyRulesetTransformedSkin(ISkin legacySkin)
|
protected ISkin GetLegacyRulesetTransformedSkin(ISkin legacySkin)
|
||||||
@ -98,6 +117,8 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
if (parentSource != null)
|
if (parentSource != null)
|
||||||
parentSource.SourceChanged -= OnSourceChanged;
|
parentSource.SourceChanged -= OnSourceChanged;
|
||||||
|
|
||||||
|
rulesetResourcesSkin?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user