1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-28 09:37:23 +08:00

Merge pull request #2334 from peppy/async-screens

Make screens always load async (fixes stutter when entering editor)
This commit is contained in:
Dean Herbert 2018-04-23 21:58:04 +09:00 committed by GitHub
commit a9ddb46ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 119 additions and 53 deletions

@ -1 +1 @@
Subproject commit f1751c27ffe2c5febece74129368596b5ad3a4e2 Subproject commit 61e676094d25436bb9e8858946f65c43d15d8e01

View File

@ -110,11 +110,13 @@ namespace osu.Game.Tests.Visual
private void selectBeatmap(string name) private void selectBeatmap(string name)
{ {
var infoBefore = infoWedge.Info; BeatmapInfoWedge.BufferedWedgeInfo infoBefore = null;
AddStep($"select {name} beatmap", () => AddStep($"select {name} beatmap", () =>
{ {
beatmap.Value = new TestWorkingBeatmap(beatmaps.First(b => b.BeatmapInfo.Ruleset.ShortName == name)); infoBefore = infoWedge.Info;
WorkingBeatmap bm = new TestWorkingBeatmap(beatmaps.First(b => b.BeatmapInfo.Ruleset.ShortName == name));
beatmap.Value = bm;
infoWedge.UpdateBeatmap(beatmap); infoWedge.UpdateBeatmap(beatmap);
}); });

View File

@ -0,0 +1,24 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
{
public class TestCasePlayerLoader : OsuTestCase
{
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player
{
InitialBeatmap = new DummyWorkingBeatmap(game),
AllowPause = false,
AllowLeadIn = false,
AllowResults = false,
})));
}
}
}

View File

@ -5,7 +5,9 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile;
using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header;
@ -17,6 +19,7 @@ namespace osu.Game.Tests.Visual
public class TestCaseUserProfile : OsuTestCase public class TestCaseUserProfile : OsuTestCase
{ {
private readonly TestUserProfileOverlay profile; private readonly TestUserProfileOverlay profile;
private APIAccess api;
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
@ -32,6 +35,12 @@ namespace osu.Game.Tests.Visual
Add(profile = new TestUserProfileOverlay()); Add(profile = new TestUserProfileOverlay());
} }
[BackgroundDependencyLoader]
private void load(APIAccess api)
{
this.api = api;
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -79,9 +88,10 @@ namespace osu.Game.Tests.Visual
{ {
Username = @"peppy", Username = @"peppy",
Id = 2, Id = 2,
IsSupporter = true,
Country = new Country { FullName = @"Australia", FlagName = @"AU" }, Country = new Country { FullName = @"Australia", FlagName = @"AU" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
})); }, api.IsLoggedIn));
checkSupporterTag(true); checkSupporterTag(true);
@ -91,7 +101,7 @@ namespace osu.Game.Tests.Visual
Id = 3103765, Id = 3103765,
Country = new Country { FullName = @"Japan", FlagName = @"JP" }, Country = new Country { FullName = @"Japan", FlagName = @"JP" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
})); }, api.IsLoggedIn));
AddStep("Hide", profile.Hide); AddStep("Hide", profile.Hide);
AddStep("Show without reload", profile.Show); AddStep("Show without reload", profile.Show);

View File

@ -1,14 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using osu.Framework.IO.Stores; using osu.Framework.IO.Stores;
namespace osu.Game.IO.Archives namespace osu.Game.IO.Archives
{ {
public abstract class ArchiveReader : IDisposable, IResourceStore<byte[]> public abstract class ArchiveReader : IResourceStore<byte[]>
{ {
/// <summary> /// <summary>
/// Opens a stream for reading a specific file from this archive. /// Opens a stream for reading a specific file from this archive.

View File

@ -188,6 +188,20 @@ namespace osu.Game
FileStore.Cleanup(); FileStore.Cleanup();
AddInternal(api); AddInternal(api);
GlobalActionContainer globalBinding;
CursorOverrideContainer = new CursorOverrideContainer { RelativeSizeAxes = Axes.Both };
CursorOverrideContainer.Child = globalBinding = new GlobalActionContainer(this)
{
RelativeSizeAxes = Axes.Both,
Child = content = new OsuTooltipContainer(CursorOverrideContainer.Cursor) { RelativeSizeAxes = Axes.Both }
};
base.Content.Add(new DrawSizePreservingFillContainer { Child = CursorOverrideContainer });
KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding);
} }
private void runMigrations() private void runMigrations()
@ -217,20 +231,6 @@ namespace osu.Game
{ {
base.LoadComplete(); base.LoadComplete();
GlobalActionContainer globalBinding;
CursorOverrideContainer = new CursorOverrideContainer { RelativeSizeAxes = Axes.Both };
CursorOverrideContainer.Child = globalBinding = new GlobalActionContainer(this)
{
RelativeSizeAxes = Axes.Both,
Child = content = new OsuTooltipContainer(CursorOverrideContainer.Cursor) { RelativeSizeAxes = Axes.Both }
};
base.Content.Add(new DrawSizePreservingFillContainer { Child = CursorOverrideContainer });
KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding);
// TODO: This is temporary until we reimplement the local FPS display. // TODO: This is temporary until we reimplement the local FPS display.
// It's just to allow end-users to access the framework FPS display without knowing the shortcut key. // It's just to allow end-users to access the framework FPS display without knowing the shortcut key.
fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay); fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay);

View File

@ -26,14 +26,14 @@ namespace osu.Game.Screens
return false; return false;
} }
public override bool Push(Screen screen) public override void Push(Screen screen)
{ {
// When trying to push a non-loaded screen, load it asynchronously and re-invoke Push // When trying to push a non-loaded screen, load it asynchronously and re-invoke Push
// once it's done. // once it's done.
if (screen.LoadState == LoadState.NotLoaded) if (screen.LoadState == LoadState.NotLoaded)
{ {
LoadComponentAsync(screen, d => Push((BackgroundScreen)d)); LoadComponentAsync(screen, d => Push((BackgroundScreen)d));
return true; return;
} }
// Make sure the in-progress loading is complete before pushing the screen. // Make sure the in-progress loading is complete before pushing the screen.
@ -41,8 +41,6 @@ namespace osu.Game.Screens
Thread.Sleep(1); Thread.Sleep(1);
base.Push(screen); base.Push(screen);
return true;
} }
protected override void Update() protected override void Update()

View File

@ -178,7 +178,7 @@ namespace osu.Game.Screens.Edit
} }
currentScreen.Beatmap.BindTo(Beatmap); currentScreen.Beatmap.BindTo(Beatmap);
screenContainer.Add(currentScreen); LoadComponentAsync(currentScreen, screenContainer.Add);
} }
protected override bool OnWheel(InputState state) protected override bool OnWheel(InputState state)

View File

@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play
private DrawableStoryboard storyboard; private DrawableStoryboard storyboard;
private Container storyboardContainer; private Container storyboardContainer;
private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true; public bool LoadedBeatmapSuccessfully => RulesetContainer?.Objects.Any() == true;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, APIAccess api, OsuConfigManager config) private void load(AudioManager audio, APIAccess api, OsuConfigManager config)
@ -86,10 +86,7 @@ namespace osu.Game.Screens.Play
WorkingBeatmap working = Beatmap.Value; WorkingBeatmap working = Beatmap.Value;
if (working is DummyWorkingBeatmap) if (working is DummyWorkingBeatmap)
{
Exit();
return; return;
}
sampleRestart = audio.Sample.Get(@"Gameplay/restart"); sampleRestart = audio.Sample.Get(@"Gameplay/restart");
@ -122,14 +119,15 @@ namespace osu.Game.Screens.Play
} }
if (!RulesetContainer.Objects.Any()) if (!RulesetContainer.Objects.Any())
throw new InvalidOperationException("Beatmap contains no hit objects!"); {
Logger.Error(new InvalidOperationException("Beatmap contains no hit objects!"), "Beatmap contains no hit objects!");
return;
}
} }
catch (Exception e) catch (Exception e)
{ {
Logger.Error(e, "Could not load beatmap sucessfully!"); Logger.Error(e, "Could not load beatmap sucessfully!");
//couldn't load, hard abort! //couldn't load, hard abort!
Exit();
return; return;
} }
@ -293,7 +291,7 @@ namespace osu.Game.Screens.Play
{ {
base.OnEntering(last); base.OnEntering(last);
if (!loadedSuccessfully) if (!LoadedBeatmapSuccessfully)
return; return;
Content.Alpha = 0; Content.Alpha = 0;
@ -343,7 +341,7 @@ namespace osu.Game.Screens.Play
return base.OnExiting(next); return base.OnExiting(next);
} }
if (loadedSuccessfully) if (LoadedBeatmapSuccessfully)
pauseContainer?.Pause(); pauseContainer?.Pause();
return true; return true;

View File

@ -159,14 +159,14 @@ namespace osu.Game.Screens.Play
loadTask = null; loadTask = null;
if (!Push(player)) //By default, we want to load the player and never be returned to.
Exit(); //Note that this may change if the player we load requested a re-run.
ValidForResume = false;
if (player.LoadedBeatmapSuccessfully)
Push(player);
else else
{ Exit();
//By default, we want to load the player and never be returned to.
//Note that this may change if the player we load requested a re-run.
ValidForResume = false;
}
}); });
}, 500); }, 500);
} }

View File

@ -16,6 +16,12 @@ namespace osu.Game.Screens.Select.Carousel
protected List<CarouselItem> InternalChildren = new List<CarouselItem>(); protected List<CarouselItem> InternalChildren = new List<CarouselItem>();
/// <summary>
/// Used to assign a monotonically increasing ID to children as they are added. This member is
/// incremented whenever a child is added.
/// </summary>
private ulong currentChildID;
public override List<DrawableCarouselItem> Drawables public override List<DrawableCarouselItem> Drawables
{ {
get get
@ -39,6 +45,7 @@ namespace osu.Game.Screens.Select.Carousel
public virtual void AddChild(CarouselItem i) public virtual void AddChild(CarouselItem i)
{ {
i.State.ValueChanged += v => ChildItemStateChanged(i, v); i.State.ValueChanged += v => ChildItemStateChanged(i, v);
i.ChildID = ++currentChildID;
InternalChildren.Add(i); InternalChildren.Add(i);
} }

View File

@ -31,6 +31,8 @@ namespace osu.Game.Screens.Select.Carousel
} }
} }
private int creationOrder;
protected CarouselItem() protected CarouselItem()
{ {
drawableRepresentation = new Lazy<DrawableCarouselItem>(CreateDrawableRepresentation); drawableRepresentation = new Lazy<DrawableCarouselItem>(CreateDrawableRepresentation);
@ -44,13 +46,18 @@ namespace osu.Game.Screens.Select.Carousel
private readonly Lazy<DrawableCarouselItem> drawableRepresentation; private readonly Lazy<DrawableCarouselItem> drawableRepresentation;
/// <summary>
/// Used as a default sort method for <see cref="CarouselItem"/>s of differing types.
/// </summary>
internal ulong ChildID;
protected abstract DrawableCarouselItem CreateDrawableRepresentation(); protected abstract DrawableCarouselItem CreateDrawableRepresentation();
public virtual void Filter(FilterCriteria criteria) public virtual void Filter(FilterCriteria criteria)
{ {
} }
public virtual int CompareTo(FilterCriteria criteria, CarouselItem other) => GetHashCode().CompareTo(other.GetHashCode()); public virtual int CompareTo(FilterCriteria criteria, CarouselItem other) => ChildID.CompareTo(other.ChildID);
} }
public enum CarouselItemState public enum CarouselItemState

View File

@ -113,6 +113,31 @@ namespace osu.Game.Skinning
string path = getPathForFile(name); string path = getPathForFile(name);
return path == null ? null : underlyingStore.Get(path); return path == null ? null : underlyingStore.Get(path);
} }
#region IDisposable Support
private bool isDisposed;
protected virtual void Dispose(bool disposing)
{
if (!isDisposed)
{
isDisposed = true;
}
}
~LegacySkinResourceStore()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
} }
} }
} }

View File

@ -15,18 +15,14 @@ namespace osu.Game.Tests.Visual
{ {
protected override string MainResourceFile => File.Exists(base.MainResourceFile) ? base.MainResourceFile : Assembly.GetExecutingAssembly().Location; protected override string MainResourceFile => File.Exists(base.MainResourceFile) ? base.MainResourceFile : Assembly.GetExecutingAssembly().Location;
private readonly TestCaseTestRunner.TestRunner runner; private TestCaseTestRunner.TestRunner runner;
public OsuTestCaseTestRunner() protected override void LoadAsyncComplete()
{ {
runner = new TestCaseTestRunner.TestRunner(); // this has to be run here rather than LoadComplete because
} // TestCase.cs is checking the IsLoaded state (on another thread) and expects
// the runner to be loaded at that point.
protected override void LoadComplete() Add(runner = new TestCaseTestRunner.TestRunner());
{
base.LoadComplete();
Add(runner);
} }
public void RunTestBlocking(TestCase test) => runner.RunTestBlocking(test); public void RunTestBlocking(TestCase test) => runner.RunTestBlocking(test);