Merge remote-tracking branch 'origin/master' into fix-more-pause-cases

# Conflicts:
#	osu.Game.Tests/Visual/Gameplay/TestCasePause.cs
This commit is contained in:
smoogipoo
2019-05-10 22:15:59 +09:00
15 changed files with 151 additions and 68 deletions

View File

@ -73,6 +73,26 @@ namespace osu.Game.Tests.Visual.Gameplay
checkFrameCount(2); checkFrameCount(2);
} }
[Test]
public void TestInitialSeekWithGameplayStart()
{
seekManualTo(1000);
createStabilityContainer(30000);
confirmSeek(1000);
checkFrameCount(0);
seekManualTo(10000);
confirmSeek(10000);
checkFrameCount(1);
seekManualTo(130000);
confirmSeek(130000);
checkFrameCount(6002);
}
[Test] [Test]
public void TestInitialSeek() public void TestInitialSeek()
{ {
@ -83,7 +103,11 @@ namespace osu.Game.Tests.Visual.Gameplay
checkFrameCount(0); checkFrameCount(0);
} }
private void createStabilityContainer() => AddStep("create container", () => mainContainer.Child = new FrameStabilityContainer().WithChild(consumer = new ClockConsumingChild())); private const int max_frames_catchup = 50;
private void createStabilityContainer(double gameplayStartTime = double.MinValue) => AddStep("create container", () =>
mainContainer.Child = new FrameStabilityContainer(gameplayStartTime) { MaxCatchUpFrames = max_frames_catchup }
.WithChild(consumer = new ClockConsumingChild()));
private void seekManualTo(double time) => AddStep($"seek manual clock to {time}", () => manualClock.CurrentTime = time); private void seekManualTo(double time) => AddStep($"seek manual clock to {time}", () => manualClock.CurrentTime = time);

View File

@ -6,6 +6,7 @@ using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Cursor;
using osu.Game.Rulesets; using osu.Game.Rulesets;
@ -31,6 +32,14 @@ namespace osu.Game.Tests.Visual.Gameplay
base.Content.Add(content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both }); base.Content.Add(content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both });
} }
[SetUpSteps]
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("resume player", () => Player.GameplayClockContainer.Start());
confirmClockRunning(true);
}
[Test] [Test]
public void TestPauseResume() public void TestPauseResume()
{ {
@ -197,6 +206,12 @@ namespace osu.Game.Tests.Visual.Gameplay
public bool FailOverlayVisible => FailOverlay.State == Visibility.Visible; public bool FailOverlayVisible => FailOverlay.State == Visibility.Visible;
public bool PauseOverlayVisible => PauseOverlay.State == Visibility.Visible; public bool PauseOverlayVisible => PauseOverlay.State == Visibility.Visible;
public override void OnEntering(IScreen last)
{
base.OnEntering(last);
GameplayClockContainer.Stop();
}
} }
} }
} }

View File

@ -65,7 +65,6 @@ namespace osu.Game.Beatmaps
protected override IQueryable<BeatmapSetInfo> AddIncludesForDeletion(IQueryable<BeatmapSetInfo> query) => protected override IQueryable<BeatmapSetInfo> AddIncludesForDeletion(IQueryable<BeatmapSetInfo> query) =>
base.AddIncludesForDeletion(query) base.AddIncludesForDeletion(query)
.Include(s => s.Metadata) .Include(s => s.Metadata)
.Include(s => s.Beatmaps).ThenInclude(b => b.Scores)
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata); .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata);

View File

@ -385,7 +385,7 @@ namespace osu.Game.Database
/// Delete multiple items. /// Delete multiple items.
/// This will post notifications tracking progress. /// This will post notifications tracking progress.
/// </summary> /// </summary>
public void Delete(List<TModel> items) public void Delete(List<TModel> items, bool silent = false)
{ {
if (items.Count == 0) return; if (items.Count == 0) return;
@ -396,7 +396,8 @@ namespace osu.Game.Database
State = ProgressNotificationState.Active, State = ProgressNotificationState.Active,
}; };
PostNotification?.Invoke(notification); if (!silent)
PostNotification?.Invoke(notification);
int i = 0; int i = 0;
@ -423,7 +424,7 @@ namespace osu.Game.Database
/// Restore multiple items that were previously deleted. /// Restore multiple items that were previously deleted.
/// This will post notifications tracking progress. /// This will post notifications tracking progress.
/// </summary> /// </summary>
public void Undelete(List<TModel> items) public void Undelete(List<TModel> items, bool silent = false)
{ {
if (!items.Any()) return; if (!items.Any()) return;
@ -434,7 +435,8 @@ namespace osu.Game.Database
State = ProgressNotificationState.Active, State = ProgressNotificationState.Active,
}; };
PostNotification?.Invoke(notification); if (!silent)
PostNotification?.Invoke(notification);
int i = 0; int i = 0;

View File

@ -155,8 +155,23 @@ namespace osu.Game
dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage));
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Host.Storage, contextFactory, Host));
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap)); dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap));
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, BeatmapManager, Host.Storage, contextFactory, Host));
// this should likely be moved to ArchiveModelManager when another case appers where it is necessary
// to have inter-dependent model managers. this could be obtained with an IHasForeign<T> interface to
// allow lookups to be done on the child (ScoreManager in this case) to perform the cascading delete.
List<ScoreInfo> getBeatmapScores(BeatmapSetInfo set)
{
var beatmapIds = BeatmapManager.QueryBeatmaps(b => b.BeatmapSetInfoID == set.ID).Select(b => b.ID).ToList();
return ScoreManager.QueryScores(s => beatmapIds.Contains(s.Beatmap.ID)).ToList();
}
BeatmapManager.ItemRemoved += i => ScoreManager.Delete(getBeatmapScores(i), true);
BeatmapManager.ItemAdded += (i, existing) => ScoreManager.Undelete(getBeatmapScores(i), true);
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore));
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory));
dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore)); dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore));

View File

@ -12,6 +12,7 @@ using osu.Game.Rulesets.Objects.Drawables;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Input; using osu.Framework.Input;
@ -59,6 +60,8 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
public Container Overlays { get; private set; } public Container Overlays { get; private set; }
public override GameplayClock FrameStableClock => frameStabilityContainer.GameplayClock;
/// <summary> /// <summary>
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>. /// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
/// </summary> /// </summary>
@ -140,11 +143,11 @@ namespace osu.Game.Rulesets.UI
public virtual PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new PlayfieldAdjustmentContainer(); public virtual PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new PlayfieldAdjustmentContainer();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config, CancellationToken? cancellationToken)
{ {
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
frameStabilityContainer = new FrameStabilityContainer frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime)
{ {
Child = KeyBindingInputManager Child = KeyBindingInputManager
.WithChild(CreatePlayfieldAdjustmentContainer() .WithChild(CreatePlayfieldAdjustmentContainer()
@ -163,16 +166,21 @@ namespace osu.Game.Rulesets.UI
applyRulesetMods(mods, config); applyRulesetMods(mods, config);
loadObjects(); loadObjects(cancellationToken);
} }
/// <summary> /// <summary>
/// Creates and adds drawable representations of hit objects to the play field. /// Creates and adds drawable representations of hit objects to the play field.
/// </summary> /// </summary>
private void loadObjects() private void loadObjects(CancellationToken? cancellationToken)
{ {
foreach (TObject h in Beatmap.HitObjects) foreach (TObject h in Beatmap.HitObjects)
{
cancellationToken?.ThrowIfCancellationRequested();
addHitObject(h); addHitObject(h);
}
cancellationToken?.ThrowIfCancellationRequested();
Playfield.PostProcess(); Playfield.PostProcess();
@ -334,6 +342,11 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
public readonly BindableBool IsPaused = new BindableBool(); public readonly BindableBool IsPaused = new BindableBool();
/// <summary>
/// The frame-stable clock which is being used for playfield display.
/// </summary>
public abstract GameplayClock FrameStableClock { get; }
/// <summary>~ /// <summary>~
/// The associated ruleset. /// The associated ruleset.
/// </summary> /// </summary>

View File

@ -17,19 +17,29 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
public class FrameStabilityContainer : Container, IHasReplayHandler public class FrameStabilityContainer : Container, IHasReplayHandler
{ {
public FrameStabilityContainer() private readonly double gameplayStartTime;
/// <summary>
/// The number of frames (per parent frame) which can be run in an attempt to catch-up to real-time.
/// </summary>
public int MaxCatchUpFrames { get; set; } = 5;
[Cached]
public GameplayClock GameplayClock { get; }
public FrameStabilityContainer(double gameplayStartTime = double.MinValue)
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
gameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock()));
GameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock()));
this.gameplayStartTime = gameplayStartTime;
} }
private readonly ManualClock manualClock; private readonly ManualClock manualClock;
private readonly FramedClock framedClock; private readonly FramedClock framedClock;
[Cached]
private GameplayClock gameplayClock;
private IFrameBasedClock parentGameplayClock; private IFrameBasedClock parentGameplayClock;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
@ -38,7 +48,7 @@ namespace osu.Game.Rulesets.UI
if (clock != null) if (clock != null)
{ {
parentGameplayClock = clock; parentGameplayClock = clock;
gameplayClock.IsPaused.BindTo(clock.IsPaused); GameplayClock.IsPaused.BindTo(clock.IsPaused);
} }
} }
@ -64,8 +74,6 @@ namespace osu.Game.Rulesets.UI
private bool isAttached => ReplayInputHandler != null; private bool isAttached => ReplayInputHandler != null;
private const int max_catch_up_updates_per_frame = 50;
private const double sixty_frame_time = 1000.0 / 60; private const double sixty_frame_time = 1000.0 / 60;
private bool firstConsumption = true; private bool firstConsumption = true;
@ -73,11 +81,11 @@ namespace osu.Game.Rulesets.UI
public override bool UpdateSubTree() public override bool UpdateSubTree()
{ {
requireMoreUpdateLoops = true; requireMoreUpdateLoops = true;
validState = !gameplayClock.IsPaused.Value; validState = !GameplayClock.IsPaused.Value;
int loops = 0; int loops = 0;
while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame) while (validState && requireMoreUpdateLoops && loops++ < MaxCatchUpFrames)
{ {
updateClock(); updateClock();
@ -116,6 +124,8 @@ namespace osu.Game.Rulesets.UI
firstConsumption = false; firstConsumption = false;
} }
else if (manualClock.CurrentTime < gameplayStartTime)
manualClock.CurrentTime = newProposedTime = Math.Min(gameplayStartTime, newProposedTime);
else if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f) else if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f)
{ {
newProposedTime = newProposedTime > manualClock.CurrentTime newProposedTime = newProposedTime > manualClock.CurrentTime
@ -160,7 +170,7 @@ namespace osu.Game.Rulesets.UI
if (parentGameplayClock == null) if (parentGameplayClock == null)
parentGameplayClock = Clock; parentGameplayClock = Clock;
Clock = gameplayClock; Clock = GameplayClock;
ProcessCustomClock = false; ProcessCustomClock = false;
} }

View File

@ -25,9 +25,9 @@ namespace osu.Game.Scoring
protected override string ImportFromStablePath => "Replays"; protected override string ImportFromStablePath => "Replays";
private readonly RulesetStore rulesets; private readonly RulesetStore rulesets;
private readonly BeatmapManager beatmaps; private readonly Func<BeatmapManager> beatmaps;
public ScoreManager(RulesetStore rulesets, BeatmapManager beatmaps, Storage storage, IDatabaseContextFactory contextFactory, IIpcHost importHost = null) public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, IDatabaseContextFactory contextFactory, IIpcHost importHost = null)
: base(storage, contextFactory, new ScoreStore(contextFactory, storage), importHost) : base(storage, contextFactory, new ScoreStore(contextFactory, storage), importHost)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
@ -43,7 +43,7 @@ namespace osu.Game.Scoring
{ {
try try
{ {
return new DatabasedLegacyScoreParser(rulesets, beatmaps).Parse(stream).ScoreInfo; return new DatabasedLegacyScoreParser(rulesets, beatmaps()).Parse(stream).ScoreInfo;
} }
catch (LegacyScoreParser.BeatmapNotFoundException e) catch (LegacyScoreParser.BeatmapNotFoundException e)
{ {
@ -53,7 +53,7 @@ namespace osu.Game.Scoring
} }
} }
public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps, Files.Store); public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store);
public List<ScoreInfo> GetAllUsableScores() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList(); public List<ScoreInfo> GetAllUsableScores() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();

View File

@ -35,6 +35,10 @@ namespace osu.Game.Screens.Play
public readonly HoldForMenuButton HoldToQuit; public readonly HoldForMenuButton HoldToQuit;
public readonly PlayerSettingsOverlay PlayerSettingsOverlay; public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
private readonly ScoreProcessor scoreProcessor;
private readonly DrawableRuleset drawableRuleset;
private readonly IReadOnlyList<Mod> mods;
private Bindable<bool> showHud; private Bindable<bool> showHud;
private readonly Container visibilityContainer; private readonly Container visibilityContainer;
private readonly BindableBool replayLoaded = new BindableBool(); private readonly BindableBool replayLoaded = new BindableBool();
@ -45,6 +49,10 @@ namespace osu.Game.Screens.Play
public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods) public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
{ {
this.scoreProcessor = scoreProcessor;
this.drawableRuleset = drawableRuleset;
this.mods = mods;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Children = new Drawable[] Children = new Drawable[]
@ -89,20 +97,21 @@ namespace osu.Game.Screens.Play
} }
} }
}; };
}
[BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
{
BindProcessor(scoreProcessor); BindProcessor(scoreProcessor);
BindDrawableRuleset(drawableRuleset); BindDrawableRuleset(drawableRuleset);
Progress.Objects = drawableRuleset.Objects; Progress.Objects = drawableRuleset.Objects;
Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value; Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value;
Progress.RequestSeek = time => RequestSeek(time); Progress.RequestSeek = time => RequestSeek(time);
Progress.ReferenceClock = drawableRuleset.FrameStableClock;
ModDisplay.Current.Value = mods; ModDisplay.Current.Value = mods;
}
[BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
{
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface); showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
showHud.ValueChanged += visible => visibilityContainer.FadeTo(visible.NewValue ? 1 : 0, duration); showHud.ValueChanged += visible => visibilityContainer.FadeTo(visible.NewValue ? 1 : 0, duration);
showHud.TriggerChange(); showHud.TriggerChange();

View File

@ -10,6 +10,7 @@ using osu.Game.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using System.Linq; using System.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -55,7 +56,9 @@ namespace osu.Game.Screens.Play
private readonly BindableBool replayLoaded = new BindableBool(); private readonly BindableBool replayLoaded = new BindableBool();
private GameplayClock gameplayClock; public IClock ReferenceClock;
private IClock gameplayClock;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuColour colours, GameplayClock clock) private void load(OsuColour colours, GameplayClock clock)
@ -154,10 +157,12 @@ namespace osu.Game.Screens.Play
if (objects == null) if (objects == null)
return; return;
double position = gameplayClock?.CurrentTime ?? Time.Current; double gameplayTime = gameplayClock?.CurrentTime ?? Time.Current;
double progress = Math.Min(1, (position - firstHitTime) / (lastHitTime - firstHitTime)); double frameStableTime = ReferenceClock?.CurrentTime ?? gameplayTime;
bar.CurrentTime = position; double progress = Math.Min(1, (frameStableTime - firstHitTime) / (lastHitTime - firstHitTime));
bar.CurrentTime = gameplayTime;
graph.Progress = (int)(graph.ColumnCount * progress); graph.Progress = (int)(graph.ColumnCount * progress);
} }
} }

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.MathUtils;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -107,9 +108,17 @@ namespace osu.Game.Screens.Play
protected override void UpdateValue(float value) protected override void UpdateValue(float value)
{ {
var xFill = value * UsableWidth; // handled in update
fill.Width = xFill; }
handleBase.X = xFill;
protected override void Update()
{
base.Update();
float newX = (float)Interpolation.Lerp(handleBase.X, NormalizedValue * UsableWidth, MathHelper.Clamp(Time.Elapsed / 40, 0, 1));
fill.Width = newX;
handleBase.X = newX;
} }
protected override void OnUserChange(double value) => OnSeek?.Invoke(value); protected override void OnUserChange(double value) => OnSeek?.Invoke(value);

View File

@ -1,6 +1,7 @@
// 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.Threading;
using osuTK; using osuTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -57,7 +58,7 @@ namespace osu.Game.Storyboards.Drawables
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(FileStore fileStore, GameplayClock clock) private void load(FileStore fileStore, GameplayClock clock, CancellationToken? cancellationToken)
{ {
if (clock != null) if (clock != null)
Clock = clock; Clock = clock;
@ -65,7 +66,11 @@ namespace osu.Game.Storyboards.Drawables
dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1)); dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1));
foreach (var layer in Storyboard.Layers) foreach (var layer in Storyboard.Layers)
{
cancellationToken?.ThrowIfCancellationRequested();
Add(layer.CreateDrawable()); Add(layer.CreateDrawable());
}
} }
private void updateLayerVisibility() private void updateLayerVisibility()

View File

@ -1,6 +1,7 @@
// 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.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -24,10 +25,12 @@ namespace osu.Game.Storyboards.Drawables
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(CancellationToken? cancellationToken)
{ {
foreach (var element in Layer.Elements) foreach (var element in Layer.Elements)
{ {
cancellationToken?.ThrowIfCancellationRequested();
if (element.IsDrawable) if (element.IsDrawable)
AddInternal(element.CreateDrawable()); AddInternal(element.CreateDrawable());
} }

View File

@ -5,11 +5,10 @@ using osu.Game.Beatmaps;
using osu.Game.Storyboards.Drawables; using osu.Game.Storyboards.Drawables;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System;
namespace osu.Game.Storyboards namespace osu.Game.Storyboards
{ {
public class Storyboard : IDisposable public class Storyboard
{ {
private readonly Dictionary<string, StoryboardLayer> layers = new Dictionary<string, StoryboardLayer>(); private readonly Dictionary<string, StoryboardLayer> layers = new Dictionary<string, StoryboardLayer>();
public IEnumerable<StoryboardLayer> Layers => layers.Values; public IEnumerable<StoryboardLayer> Layers => layers.Values;
@ -56,30 +55,5 @@ namespace osu.Game.Storyboards
drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f);
return drawable; return drawable;
} }
#region Disposal
~Storyboard()
{
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

@ -1,4 +1,4 @@
// 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 System.Linq;
@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual
} }
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public virtual void SetUpSteps()
{ {
AddStep(ruleset.RulesetInfo.Name, loadPlayer); AddStep(ruleset.RulesetInfo.Name, loadPlayer);
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1); AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);