1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 15:27:26 +08:00

Merge pull request #8709 from frenzibyte/cache-ruleset-dependencies-for-tests

Cache ruleset dependencies for test scenes that require it
This commit is contained in:
Dan Balasescu 2020-06-15 20:17:11 +09:00 committed by GitHub
commit 83f26bcb81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 265 additions and 94 deletions

View File

@ -87,11 +87,11 @@ namespace osu.Game.Tests.Gameplay
this.resourceName = resourceName;
}
public byte[] Get(string name) => name == resourceName ? TestResources.GetStore().Get("Resources/test-sample.mp3") : null;
public byte[] Get(string name) => name == resourceName ? TestResources.GetStore().Get("Resources/Samples/test-sample.mp3") : null;
public Task<byte[]> GetAsync(string name) => name == resourceName ? TestResources.GetStore().GetAsync("Resources/test-sample.mp3") : null;
public Task<byte[]> GetAsync(string name) => name == resourceName ? TestResources.GetStore().GetAsync("Resources/Samples/test-sample.mp3") : null;
public Stream GetStream(string name) => name == resourceName ? TestResources.GetStore().GetStream("Resources/test-sample.mp3") : null;
public Stream GetStream(string name) => name == resourceName ? TestResources.GetStore().GetStream("Resources/Samples/test-sample.mp3") : null;
public IEnumerable<string> GetAvailableResources() => new[] { resourceName };

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,95 @@
// 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.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration.Tracking;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual;
namespace osu.Game.Tests.Testing
{
/// <summary>
/// A test scene ensuring the dependencies for the
/// provided ruleset below are cached at the base implementation.
/// </summary>
[HeadlessTest]
public class TestSceneRulesetDependencies : OsuTestScene
{
protected override Ruleset CreateRuleset() => new TestRuleset();
[Test]
public void TestRetrieveTexture()
{
AddAssert("ruleset texture retrieved", () =>
Dependencies.Get<TextureStore>().Get(@"test-image") != null);
}
[Test]
public void TestRetrieveSample()
{
AddAssert("ruleset sample retrieved", () =>
Dependencies.Get<ISampleStore>().Get(@"test-sample") != null);
}
[Test]
public void TestResolveConfigManager()
{
AddAssert("ruleset config resolved", () =>
Dependencies.Get<TestRulesetConfigManager>() != null);
}
private class TestRuleset : Ruleset
{
public override string Description => string.Empty;
public override string ShortName => string.Empty;
public TestRuleset()
{
// temporary ID to let RulesetConfigCache pass our
// config manager to the ruleset dependencies.
RulesetInfo.ID = -1;
}
public override IResourceStore<byte[]> CreateResourceStore() => new NamespacedResourceStore<byte[]>(TestResources.GetStore(), @"Resources");
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new TestRulesetConfigManager();
public override IEnumerable<Mod> GetModsFor(ModType type) => Array.Empty<Mod>();
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => null;
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null;
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => null;
}
private class TestRulesetConfigManager : IRulesetConfigManager
{
public void Load()
{
}
public bool Save() => true;
public TrackedSettings CreateTrackedSettings() => new TrackedSettings();
public void LoadInto(TrackedSettings settings)
{
}
public void Dispose()
{
}
}
}
}

View File

@ -11,20 +11,13 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.IO.Stores;
using osu.Game.Configuration;
using osu.Game.Graphics.Cursor;
using osu.Game.Input.Handlers;
@ -63,10 +56,6 @@ namespace osu.Game.Rulesets.UI
private readonly Lazy<Playfield> playfield;
private TextureStore textureStore;
private ISampleStore localSampleStore;
/// <summary>
/// The playfield.
/// </summary>
@ -113,6 +102,8 @@ namespace osu.Game.Rulesets.UI
private OnScreenDisplay onScreenDisplay;
private DrawableRulesetDependencies dependencies;
/// <summary>
/// Creates a ruleset visualisation for the provided ruleset and beatmap.
/// </summary>
@ -147,30 +138,13 @@ namespace osu.Game.Rulesets.UI
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies = new DrawableRulesetDependencies(Ruleset, base.CreateChildDependencies(parent));
var resources = Ruleset.CreateResourceStore();
if (resources != null)
{
textureStore = new TextureStore(new TextureLoaderStore(new NamespacedResourceStore<byte[]>(resources, "Textures")));
textureStore.AddStore(dependencies.Get<TextureStore>());
dependencies.Cache(textureStore);
localSampleStore = dependencies.Get<AudioManager>().GetSampleStore(new NamespacedResourceStore<byte[]>(resources, "Samples"));
localSampleStore.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY;
dependencies.CacheAs<ISampleStore>(new FallbackSampleStore(localSampleStore, dependencies.Get<ISampleStore>()));
}
Config = dependencies.RulesetConfigManager;
onScreenDisplay = dependencies.Get<OnScreenDisplay>();
Config = dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);
if (Config != null)
{
dependencies.Cache(Config);
onScreenDisplay?.BeginTracking(this, Config);
}
return dependencies;
}
@ -362,13 +336,14 @@ namespace osu.Game.Rulesets.UI
{
base.Dispose(isDisposing);
localSampleStore?.Dispose();
if (Config != null)
{
onScreenDisplay?.StopTracking(this, Config);
Config = null;
}
// Dispose the components created by this dependency container.
dependencies?.Dispose();
}
}
@ -524,62 +499,4 @@ namespace osu.Game.Rulesets.UI
{
}
}
/// <summary>
/// A sample store which adds a fallback source.
/// </summary>
/// <remarks>
/// This is a temporary implementation to workaround ISampleStore limitations.
/// </remarks>
public class FallbackSampleStore : ISampleStore
{
private readonly ISampleStore primary;
private readonly ISampleStore secondary;
public FallbackSampleStore(ISampleStore primary, ISampleStore secondary)
{
this.primary = primary;
this.secondary = secondary;
}
public SampleChannel Get(string name) => primary.Get(name) ?? secondary.Get(name);
public Task<SampleChannel> GetAsync(string name) => primary.GetAsync(name) ?? secondary.GetAsync(name);
public Stream GetStream(string name) => primary.GetStream(name) ?? secondary.GetStream(name);
public IEnumerable<string> GetAvailableResources() => throw new NotSupportedException();
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotSupportedException();
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotSupportedException();
public BindableNumber<double> Volume => throw new NotSupportedException();
public BindableNumber<double> Balance => throw new NotSupportedException();
public BindableNumber<double> Frequency => throw new NotSupportedException();
public BindableNumber<double> Tempo => throw new NotSupportedException();
public IBindable<double> GetAggregate(AdjustableProperty type) => throw new NotSupportedException();
public IBindable<double> AggregateVolume => throw new NotSupportedException();
public IBindable<double> AggregateBalance => throw new NotSupportedException();
public IBindable<double> AggregateFrequency => throw new NotSupportedException();
public IBindable<double> AggregateTempo => throw new NotSupportedException();
public int PlaybackConcurrency
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
public void Dispose()
{
}
}
}

View File

@ -0,0 +1,148 @@
// 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.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Game.Rulesets.Configuration;
namespace osu.Game.Rulesets.UI
{
public class DrawableRulesetDependencies : DependencyContainer, IDisposable
{
/// <summary>
/// The texture store to be used for the ruleset.
/// </summary>
public TextureStore TextureStore { get; }
/// <summary>
/// The sample store to be used for the ruleset.
/// </summary>
/// <remarks>
/// This is the local sample store pointing to the ruleset sample resources,
/// the cached sample store (<see cref="FallbackSampleStore"/>) retrieves from
/// this store and falls back to the parent store if this store doesn't have the requested sample.
/// </remarks>
public ISampleStore SampleStore { get; }
/// <summary>
/// The ruleset config manager.
/// </summary>
public IRulesetConfigManager RulesetConfigManager { get; private set; }
public DrawableRulesetDependencies(Ruleset ruleset, IReadOnlyDependencyContainer parent)
: base(parent)
{
var resources = ruleset.CreateResourceStore();
if (resources != null)
{
TextureStore = new TextureStore(new TextureLoaderStore(new NamespacedResourceStore<byte[]>(resources, @"Textures")));
TextureStore.AddStore(parent.Get<TextureStore>());
Cache(TextureStore);
SampleStore = parent.Get<AudioManager>().GetSampleStore(new NamespacedResourceStore<byte[]>(resources, @"Samples"));
SampleStore.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY;
CacheAs<ISampleStore>(new FallbackSampleStore(SampleStore, parent.Get<ISampleStore>()));
}
RulesetConfigManager = parent.Get<RulesetConfigCache>().GetConfigFor(ruleset);
if (RulesetConfigManager != null)
Cache(RulesetConfigManager);
}
#region Disposal
~DrawableRulesetDependencies()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool isDisposed;
protected void Dispose(bool disposing)
{
if (isDisposed)
return;
isDisposed = true;
SampleStore?.Dispose();
RulesetConfigManager = null;
}
#endregion
}
/// <summary>
/// A sample store which adds a fallback source.
/// </summary>
/// <remarks>
/// This is a temporary implementation to workaround ISampleStore limitations.
/// </remarks>
public class FallbackSampleStore : ISampleStore
{
private readonly ISampleStore primary;
private readonly ISampleStore secondary;
public FallbackSampleStore(ISampleStore primary, ISampleStore secondary)
{
this.primary = primary;
this.secondary = secondary;
}
public SampleChannel Get(string name) => primary.Get(name) ?? secondary.Get(name);
public Task<SampleChannel> GetAsync(string name) => primary.GetAsync(name) ?? secondary.GetAsync(name);
public Stream GetStream(string name) => primary.GetStream(name) ?? secondary.GetStream(name);
public IEnumerable<string> GetAvailableResources() => throw new NotSupportedException();
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotSupportedException();
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotSupportedException();
public BindableNumber<double> Volume => throw new NotSupportedException();
public BindableNumber<double> Balance => throw new NotSupportedException();
public BindableNumber<double> Frequency => throw new NotSupportedException();
public BindableNumber<double> Tempo => throw new NotSupportedException();
public IBindable<double> GetAggregate(AdjustableProperty type) => throw new NotSupportedException();
public IBindable<double> AggregateVolume => throw new NotSupportedException();
public IBindable<double> AggregateBalance => throw new NotSupportedException();
public IBindable<double> AggregateFrequency => throw new NotSupportedException();
public IBindable<double> AggregateTempo => throw new NotSupportedException();
public int PlaybackConcurrency
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
public void Dispose()
{
}
}
}

View File

@ -22,6 +22,7 @@ using osu.Game.Database;
using osu.Game.Online.API;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Screens;
using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps;
@ -38,6 +39,8 @@ namespace osu.Game.Tests.Visual
protected new OsuScreenDependencies Dependencies { get; private set; }
private DrawableRulesetDependencies rulesetDependencies;
private Lazy<Storage> localStorage;
protected Storage LocalStorage => localStorage.Value;
@ -66,7 +69,13 @@ namespace osu.Game.Tests.Visual
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
Dependencies = new OsuScreenDependencies(false, base.CreateChildDependencies(parent));
var baseDependencies = base.CreateChildDependencies(parent);
var providedRuleset = CreateRuleset();
if (providedRuleset != null)
baseDependencies = rulesetDependencies = new DrawableRulesetDependencies(providedRuleset, baseDependencies);
Dependencies = new OsuScreenDependencies(false, baseDependencies);
Beatmap = Dependencies.Beatmap;
Beatmap.SetDefault();
@ -153,6 +162,8 @@ namespace osu.Game.Tests.Visual
{
base.Dispose(isDisposing);
rulesetDependencies?.Dispose();
if (Beatmap?.Value.TrackLoaded == true)
Beatmap.Value.Track.Stop();