From fc0b297232b46885454e65af4c42c518bb428b08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Mar 2019 18:06:24 +0900 Subject: [PATCH 01/21] Fix menu cursor not displaying outside of gameplay scaling area --- osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs | 6 +++--- .../{GameplayCursor.cs => GameplayCursorContainer.cs} | 4 ++-- osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs | 2 +- osu.Game/Rulesets/UI/RulesetContainer.cs | 10 ++++++++-- osu.Game/Screens/Play/Player.cs | 7 +------ 5 files changed, 15 insertions(+), 14 deletions(-) rename osu.Game.Rulesets.Osu/UI/Cursor/{GameplayCursor.cs => GameplayCursorContainer.cs} (98%) diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs index 3d553c334f..5c1e775c01 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs @@ -16,18 +16,18 @@ namespace osu.Game.Rulesets.Osu.Tests [TestFixture] public class TestCaseGameplayCursor : OsuTestCase, IProvideCursor { - private GameplayCursor cursor; + private GameplayCursorContainer cursorContainer; public override IReadOnlyList RequiredTypes => new[] { typeof(CursorTrail) }; - public CursorContainer Cursor => cursor; + public CursorContainer Cursor => cursorContainer; public bool ProvidingUserCursor => true; [BackgroundDependencyLoader] private void load() { - Add(cursor = new GameplayCursor { RelativeSizeAxes = Axes.Both }); + Add(cursorContainer = new GameplayCursorContainer { RelativeSizeAxes = Axes.Both }); } } } diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs similarity index 98% rename from osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs rename to osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs index ef126cdf7d..ca8368155f 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.UI.Cursor { - public class GameplayCursor : CursorContainer, IKeyBindingHandler + public class GameplayCursorContainer : CursorContainer, IKeyBindingHandler { protected override Drawable CreateCursor() => new OsuCursor(); @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Container fadeContainer; - public GameplayCursor() + public GameplayCursorContainer() { InternalChild = fadeContainer = new Container { diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs index 85b72cbb5b..805bbfb4d4 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs @@ -60,6 +60,6 @@ namespace osu.Game.Rulesets.Osu.UI } } - protected override CursorContainer CreateCursor() => new GameplayCursor(); + protected override CursorContainer CreateCursor() => new GameplayCursorContainer(); } } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 1c29cf4e2b..c9ad7bb5ec 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -16,7 +16,9 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; +using osu.Framework.Input.Events; using osu.Game.Configuration; +using osu.Game.Graphics.Cursor; using osu.Game.Input.Handlers; using osu.Game.Overlays; using osu.Game.Replays; @@ -32,7 +34,7 @@ namespace osu.Game.Rulesets.UI /// Should not be derived - derive instead. /// /// - public abstract class RulesetContainer : Container + public abstract class RulesetContainer : Container, IProvideCursor { /// /// The selected variant. @@ -77,7 +79,11 @@ namespace osu.Game.Rulesets.UI /// /// The cursor provided by this . May be null if no cursor is provided. /// - public readonly CursorContainer Cursor; + public CursorContainer Cursor { get; } + + public bool ProvidingUserCursor => Cursor != null && !HasReplayLoaded.Value; + + protected override bool OnHover(HoverEvent e) => true; // required for IProvideCursor public readonly Ruleset Ruleset; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ee59df0e98..1518ee2f32 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -11,7 +11,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Screens; @@ -20,7 +19,6 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Rulesets; @@ -34,7 +32,7 @@ using osu.Game.Storyboards.Drawables; namespace osu.Game.Screens.Play { - public class Player : ScreenWithBeatmapBackground, IProvideCursor + public class Player : ScreenWithBeatmapBackground { protected override bool AllowBackButton => false; // handled by HoldForMenuButton @@ -59,9 +57,6 @@ namespace osu.Game.Screens.Play public int RestartCount; - public CursorContainer Cursor => RulesetContainer.Cursor; - public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value; - private IAdjustableClock sourceClock; /// From 5411c630939b90fa601d8c79ee8da8613e355a6a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Mar 2019 18:06:24 +0900 Subject: [PATCH 02/21] Fix menu cursor not displaying outside of gameplay scaling area --- osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs | 6 +++--- .../{GameplayCursor.cs => GameplayCursorContainer.cs} | 4 ++-- osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs | 2 +- osu.Game/Rulesets/UI/RulesetContainer.cs | 10 ++++++++-- osu.Game/Screens/Play/Player.cs | 7 +------ 5 files changed, 15 insertions(+), 14 deletions(-) rename osu.Game.Rulesets.Osu/UI/Cursor/{GameplayCursor.cs => GameplayCursorContainer.cs} (98%) diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs index 3d553c334f..5c1e775c01 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseGameplayCursor.cs @@ -16,18 +16,18 @@ namespace osu.Game.Rulesets.Osu.Tests [TestFixture] public class TestCaseGameplayCursor : OsuTestCase, IProvideCursor { - private GameplayCursor cursor; + private GameplayCursorContainer cursorContainer; public override IReadOnlyList RequiredTypes => new[] { typeof(CursorTrail) }; - public CursorContainer Cursor => cursor; + public CursorContainer Cursor => cursorContainer; public bool ProvidingUserCursor => true; [BackgroundDependencyLoader] private void load() { - Add(cursor = new GameplayCursor { RelativeSizeAxes = Axes.Both }); + Add(cursorContainer = new GameplayCursorContainer { RelativeSizeAxes = Axes.Both }); } } } diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs similarity index 98% rename from osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs rename to osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs index ef126cdf7d..ca8368155f 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.UI.Cursor { - public class GameplayCursor : CursorContainer, IKeyBindingHandler + public class GameplayCursorContainer : CursorContainer, IKeyBindingHandler { protected override Drawable CreateCursor() => new OsuCursor(); @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Container fadeContainer; - public GameplayCursor() + public GameplayCursorContainer() { InternalChild = fadeContainer = new Container { diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs index 85b72cbb5b..805bbfb4d4 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs @@ -60,6 +60,6 @@ namespace osu.Game.Rulesets.Osu.UI } } - protected override CursorContainer CreateCursor() => new GameplayCursor(); + protected override CursorContainer CreateCursor() => new GameplayCursorContainer(); } } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 1c29cf4e2b..c9ad7bb5ec 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -16,7 +16,9 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; +using osu.Framework.Input.Events; using osu.Game.Configuration; +using osu.Game.Graphics.Cursor; using osu.Game.Input.Handlers; using osu.Game.Overlays; using osu.Game.Replays; @@ -32,7 +34,7 @@ namespace osu.Game.Rulesets.UI /// Should not be derived - derive instead. /// /// - public abstract class RulesetContainer : Container + public abstract class RulesetContainer : Container, IProvideCursor { /// /// The selected variant. @@ -77,7 +79,11 @@ namespace osu.Game.Rulesets.UI /// /// The cursor provided by this . May be null if no cursor is provided. /// - public readonly CursorContainer Cursor; + public CursorContainer Cursor { get; } + + public bool ProvidingUserCursor => Cursor != null && !HasReplayLoaded.Value; + + protected override bool OnHover(HoverEvent e) => true; // required for IProvideCursor public readonly Ruleset Ruleset; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 44707c74f5..0f4fa3e762 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -11,7 +11,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Screens; @@ -20,7 +19,6 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Rulesets; @@ -34,7 +32,7 @@ using osu.Game.Storyboards.Drawables; namespace osu.Game.Screens.Play { - public class Player : ScreenWithBeatmapBackground, IProvideCursor + public class Player : ScreenWithBeatmapBackground { protected override bool AllowBackButton => false; // handled by HoldForMenuButton @@ -59,9 +57,6 @@ namespace osu.Game.Screens.Play public int RestartCount; - public CursorContainer Cursor => RulesetContainer.Cursor; - public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value; - private IAdjustableClock sourceClock; /// From acf518c20816b9ca61d1c9897c6aea94d957e4f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Mar 2019 12:34:58 +0900 Subject: [PATCH 03/21] Move cursor inside playfield --- .../Edit/OsuEditRulesetContainer.cs | 7 +++++-- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 5 +++++ osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs | 4 ---- osu.Game/Rulesets/UI/Playfield.cs | 15 +++++++++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 12 ++---------- osu.Game/Screens/Play/Player.cs | 4 ---- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs index c293a5a4f8..8ee07f6467 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs @@ -16,8 +16,11 @@ namespace osu.Game.Rulesets.Osu.Edit { } - protected override CursorContainer CreateCursor() => null; + protected override Playfield CreatePlayfield() => new OsuPlayfieldNoCursor { Size = Vector2.One }; - protected override Playfield CreatePlayfield() => new OsuPlayfield { Size = Vector2.One }; + private class OsuPlayfieldNoCursor : OsuPlayfield + { + protected override CursorContainer CreateCursor() => null; + } } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 2db2b45540..e2be955200 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -10,7 +10,9 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Connections; using osu.Game.Rulesets.UI; using System.Linq; +using osu.Framework.Graphics.Cursor; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu.UI.Cursor; namespace osu.Game.Rulesets.Osu.UI { @@ -34,6 +36,7 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + Cursor, connectionLayer = new FollowPointRenderer { RelativeSizeAxes = Axes.Both, @@ -54,6 +57,8 @@ namespace osu.Game.Rulesets.Osu.UI }; } + protected override CursorContainer CreateCursor() => new GameplayCursorContainer(); + public override void Add(DrawableHitObject h) { h.OnNewResult += onNewResult; diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs index 805bbfb4d4..81482a9a01 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework.Graphics.Cursor; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Input.Handlers; @@ -13,7 +12,6 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Osu.Scoring; -using osu.Game.Rulesets.Osu.UI.Cursor; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; @@ -59,7 +57,5 @@ namespace osu.Game.Rulesets.Osu.UI return first.StartTime - first.TimePreempt; } } - - protected override CursorContainer CreateCursor() => new GameplayCursorContainer(); } } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 3b8a7353c6..c1cce52c8c 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osuTK; @@ -47,6 +48,8 @@ namespace osu.Game.Rulesets.UI /// public readonly BindableBool DisplayJudgements = new BindableBool(true); + public readonly BindableBool HasReplayLoaded = new BindableBool(); + /// /// Creates a new . /// @@ -55,6 +58,8 @@ namespace osu.Game.Rulesets.UI RelativeSizeAxes = Axes.Both; hitObjectContainerLazy = new Lazy(CreateHitObjectContainer); + + Cursor = CreateCursor(); } private WorkingBeatmap beatmap; @@ -82,6 +87,16 @@ namespace osu.Game.Rulesets.UI /// The DrawableHitObject to remove. public virtual bool Remove(DrawableHitObject h) => HitObjectContainer.Remove(h); + /// + /// Creates the cursor. May be null if no cursor is required. + /// + protected virtual CursorContainer CreateCursor() => null; + + /// + /// The cursor provided by this . May be null if no cursor is provided. + /// + public CursorContainer Cursor { get; } + /// /// Registers a as a nested . /// This does not add the to the draw hierarchy. diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index c9ad7bb5ec..ed5f23dc7f 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -76,12 +76,9 @@ namespace osu.Game.Rulesets.UI /// public Container Overlays { get; protected set; } - /// - /// The cursor provided by this . May be null if no cursor is provided. - /// - public CursorContainer Cursor { get; } + public CursorContainer Cursor => Playfield.Cursor; - public bool ProvidingUserCursor => Cursor != null && !HasReplayLoaded.Value; + public bool ProvidingUserCursor => Playfield.Cursor != null && !HasReplayLoaded.Value; protected override bool OnHover(HoverEvent e) => true; // required for IProvideCursor @@ -107,8 +104,6 @@ namespace osu.Game.Rulesets.UI KeyBindingInputManager.UseParentInput = !paused.NewValue; }; - - Cursor = CreateCursor(); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -265,9 +260,6 @@ namespace osu.Game.Rulesets.UI Playfield }); - if (Cursor != null) - KeyBindingInputManager.Add(Cursor); - InternalChildren = new Drawable[] { KeyBindingInputManager, diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0f4fa3e762..59349edcaa 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -193,10 +193,6 @@ namespace osu.Game.Screens.Play Origin = Anchor.Centre, Breaks = beatmap.Breaks }, - new ScalingContainer(ScalingMode.Gameplay) - { - Child = RulesetContainer.Cursor?.CreateProxy() ?? new Container(), - }, HUDOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, adjustableClock) { Anchor = Anchor.Centre, From 18826b3a5908056b76d7fad468a68fa3940b1148 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Mar 2019 17:12:57 +0900 Subject: [PATCH 04/21] Adjust cursor scale for its new surroundings --- osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs index ca8368155f..8c6723f5be 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursorContainer.cs @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor public OsuCursor() { Origin = Anchor.Centre; - Size = new Vector2(42); + Size = new Vector2(28); } protected override void SkinChanged(ISkinSource skin, bool allowFallback) From 7aa30ca3f67f36ad07dea543d3f9f21305b5df17 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Mar 2019 17:23:13 +0900 Subject: [PATCH 05/21] Change method of cursor creation --- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 5 +---- osu.Game/Rulesets/UI/Playfield.cs | 11 ++--------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index e2be955200..47a064beee 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -10,7 +10,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Connections; using osu.Game.Rulesets.UI; using System.Linq; -using osu.Framework.Graphics.Cursor; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.UI.Cursor; @@ -36,7 +35,6 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - Cursor, connectionLayer = new FollowPointRenderer { RelativeSizeAxes = Axes.Both, @@ -53,12 +51,11 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, Depth = -1, }, + Cursor = new GameplayCursorContainer(), } }; } - protected override CursorContainer CreateCursor() => new GameplayCursorContainer(); - public override void Add(DrawableHitObject h) { h.OnNewResult += onNewResult; diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index c1cce52c8c..708db55c4d 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -58,8 +58,6 @@ namespace osu.Game.Rulesets.UI RelativeSizeAxes = Axes.Both; hitObjectContainerLazy = new Lazy(CreateHitObjectContainer); - - Cursor = CreateCursor(); } private WorkingBeatmap beatmap; @@ -88,14 +86,9 @@ namespace osu.Game.Rulesets.UI public virtual bool Remove(DrawableHitObject h) => HitObjectContainer.Remove(h); /// - /// Creates the cursor. May be null if no cursor is required. + /// The cursor currently being used by this . May be null if no cursor is provided. /// - protected virtual CursorContainer CreateCursor() => null; - - /// - /// The cursor provided by this . May be null if no cursor is provided. - /// - public CursorContainer Cursor { get; } + public CursorContainer Cursor { get; protected set; } /// /// Registers a as a nested . From 62716851a1cc33875f68bb180c0630180b3ea608 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Mar 2019 17:36:25 +0900 Subject: [PATCH 06/21] Revert some unnecessary changes --- osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs | 6 ++++-- osu.Game/Rulesets/UI/Playfield.cs | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs index 8ee07f6467..7886a2393c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Graphics.Cursor; using osu.Game.Beatmaps; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; @@ -20,7 +19,10 @@ namespace osu.Game.Rulesets.Osu.Edit private class OsuPlayfieldNoCursor : OsuPlayfield { - protected override CursorContainer CreateCursor() => null; + public OsuPlayfieldNoCursor() + { + Cursor?.Expire(); + } } } } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 708db55c4d..f0c2b8859c 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -48,8 +48,6 @@ namespace osu.Game.Rulesets.UI /// public readonly BindableBool DisplayJudgements = new BindableBool(true); - public readonly BindableBool HasReplayLoaded = new BindableBool(); - /// /// Creates a new . /// From ffe53411f61a906338b25a92e49a95e80a75a467 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Mar 2019 17:44:58 +0900 Subject: [PATCH 07/21] Add back cursor proxying --- osu.Game/Screens/Play/Player.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 59349edcaa..715a414710 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -176,7 +176,7 @@ namespace osu.Game.Screens.Play OnRetry = restart, OnQuit = performUserRequestedExit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, - Children = new Container[] + Children = new[] { StoryboardContainer = CreateStoryboardContainer(), new ScalingContainer(ScalingMode.Gameplay) @@ -193,6 +193,8 @@ namespace osu.Game.Screens.Play Origin = Anchor.Centre, Breaks = beatmap.Breaks }, + // display the cursor above some HUD elements. + RulesetContainer.Cursor?.CreateProxy() ?? new Container(), HUDOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, adjustableClock) { Anchor = Anchor.Centre, From 5de6e29294d07dac6823673d6e9c6d3146f913c4 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 6 Mar 2019 17:13:41 +0900 Subject: [PATCH 08/21] Reset currentRoom state when cancelling room creation --- osu.Game/Screens/Multi/Match/MatchSubScreen.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index a71106872e..902a8c1c57 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -53,6 +53,9 @@ namespace osu.Game.Screens.Multi.Match private MatchLeaderboard leaderboard; + [Resolved] + private Bindable currentRoom { get; set; } + public MatchSubScreen(Room room) { Title = room.RoomID.Value == null ? "New room" : room.Name.Value; @@ -182,6 +185,10 @@ namespace osu.Game.Screens.Multi.Match public override bool OnExiting(IScreen next) { RoomManager?.PartRoom(); + + if (roomId.Value == null) + currentRoom.Value = new Room(); + return base.OnExiting(next); } From 6e5ea78ca258e4a22e4ed36041959cc615126d5e Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 6 Mar 2019 17:13:28 +0900 Subject: [PATCH 09/21] Fix some nullref crashes when escaping out of new room creation --- osu.Game/Screens/Multi/Match/Components/Header.cs | 4 +++- osu.Game/Screens/Select/MatchSongSelect.cs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/Components/Header.cs b/osu.Game/Screens/Multi/Match/Components/Header.cs index 6a6a1f274c..e1592532a3 100644 --- a/osu.Game/Screens/Multi/Match/Components/Header.cs +++ b/osu.Game/Screens/Multi/Match/Components/Header.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -13,6 +14,7 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; using osu.Game.Overlays.SearchableList; +using osu.Game.Rulesets.Mods; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Play.HUD; using osuTK; @@ -108,7 +110,7 @@ namespace osu.Game.Screens.Multi.Match.Components }, }; - CurrentItem.BindValueChanged(item => modDisplay.Current.Value = item.NewValue?.RequiredMods, true); + CurrentItem.BindValueChanged(item => modDisplay.Current.Value = item.NewValue?.RequiredMods ?? Enumerable.Empty(), true); beatmapButton.Action = () => RequestBeatmapSelection?.Invoke(); } diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index f6d758df29..fcd07384e4 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -61,7 +62,7 @@ namespace osu.Game.Screens.Select return true; Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value?.Beatmap); - Beatmap.Value.Mods.Value = selectedMods.Value = CurrentItem.Value?.RequiredMods; + Beatmap.Value.Mods.Value = selectedMods.Value = CurrentItem.Value?.RequiredMods ?? Enumerable.Empty(); Ruleset.Value = CurrentItem.Value?.Ruleset; Beatmap.Disabled = true; From 58ef397f4ffaa3d5a73b544eb7fa80409a02a3e5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Mar 2019 20:30:14 +0900 Subject: [PATCH 10/21] Move all clock related gameplay logic inside GameplayClockContainer --- .../Screens/Play/GameplayClockContainer.cs | 151 +++++++++++ .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 2 + osu.Game/Screens/Play/HUDOverlay.cs | 10 +- .../Screens/Play/PausableGameplayContainer.cs | 65 ++--- osu.Game/Screens/Play/Player.cs | 246 ++++++++---------- .../Play/PlayerSettings/PlaybackSettings.cs | 29 +-- 6 files changed, 292 insertions(+), 211 deletions(-) create mode 100644 osu.Game/Screens/Play/GameplayClockContainer.cs diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs new file mode 100644 index 0000000000..f769bfd326 --- /dev/null +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -0,0 +1,151 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Screens.Play +{ + /// + /// Manages the various intricacies of the gameplay clock. + /// + public class GameplayClockContainer : Container + { + private readonly WorkingBeatmap beatmap; + + /// + /// The original source (usually a 's track). + /// + private readonly IAdjustableClock sourceClock; + + public readonly BindableBool IsPaused = new BindableBool(); + + /// + /// The decoupled clock used for gameplay. Should be used for seeks and clock control. + /// + private readonly DecoupleableInterpolatingFramedClock adjustableClock; + + /// + /// The final clock which is exposed to underlying components. + /// + [Cached] + private readonly GameplayClock gameplayClock; + + public readonly Bindable UserPlaybackRate = new BindableDouble(1) + { + Default = 1, + MinValue = 0.5, + MaxValue = 2, + Precision = 0.1, + }; + + private Bindable userAudioOffset; + + private readonly FramedOffsetClock offsetClock; + + public GameplayClockContainer(WorkingBeatmap beatmap, bool allowLeadIn, double gameplayStartTime) + { + RelativeSizeAxes = Axes.Both; + + this.beatmap = beatmap; + + sourceClock = (IAdjustableClock)beatmap.Track ?? new StopwatchClock(); + + adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; + + adjustableClock.Seek(allowLeadIn + ? Math.Min(0, gameplayStartTime - beatmap.BeatmapInfo.AudioLeadIn) + : gameplayStartTime); + + adjustableClock.ProcessFrame(); + + // Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited. + // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. + var platformOffsetClock = new FramedOffsetClock(adjustableClock) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 22 : 0 }; + + // the final usable gameplay clock with user-set offsets applied. + offsetClock = new FramedOffsetClock(platformOffsetClock); + + // the clock to be exposed via DI to children. + gameplayClock = new GameplayClock(offsetClock); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + userAudioOffset.BindValueChanged(offset => offsetClock.Offset = offset.NewValue, true); + + UserPlaybackRate.ValueChanged += _ => updateRate(); + } + + public void Restart() + { + Task.Run(() => + { + sourceClock.Reset(); + + Schedule(() => + { + adjustableClock.ChangeSource(sourceClock); + updateRate(); + + this.Delay(750).Schedule(() => + { + if (!IsPaused.Value) + { + adjustableClock.Start(); + } + }); + }); + }); + } + + public void Start() + { + // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time + // This accounts for the audio clock source potentially taking time to enter a completely stopped state + adjustableClock.Seek(adjustableClock.CurrentTime); + adjustableClock.Start(); + } + + public void Seek(double time) => adjustableClock.Seek(time); + + public void Stop() => adjustableClock.Stop(); + + public void ResetLocalAdjustments() + { + // In the case of replays, we may have changed the playback rate. + UserPlaybackRate.Value = 1; + } + + protected override void Update() + { + if (!IsPaused.Value) + offsetClock.ProcessFrame(); + + base.Update(); + } + + private void updateRate() + { + if (sourceClock == null) return; + + sourceClock.Rate = 1; + foreach (var mod in beatmap.Mods.Value.OfType()) + mod.ApplyToClock(sourceClock); + + sourceClock.Rate *= UserPlaybackRate.Value; + } + } +} diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index d3dba88281..e99f6d836e 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -19,7 +19,9 @@ namespace osu.Game.Screens.Play.HUD public readonly PlaybackSettings PlaybackSettings; public readonly VisualSettings VisualSettings; + //public readonly CollectionSettings CollectionSettings; + //public readonly DiscussionSettings DiscussionSettings; public PlayerSettingsOverlay() diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index a19b0d1e5c..4fd0572c1a 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; -using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; @@ -40,7 +40,9 @@ namespace osu.Game.Screens.Play private static bool hasShownNotificationOnce; - public HUDOverlay(ScoreProcessor scoreProcessor, RulesetContainer rulesetContainer, WorkingBeatmap working, IAdjustableClock adjustableClock) + public Action RequestSeek; + + public HUDOverlay(ScoreProcessor scoreProcessor, RulesetContainer rulesetContainer, WorkingBeatmap working) { RelativeSizeAxes = Axes.Both; @@ -92,11 +94,9 @@ namespace osu.Game.Screens.Play Progress.Objects = rulesetContainer.Objects; Progress.AllowSeeking = rulesetContainer.HasReplayLoaded.Value; - Progress.RequestSeek = pos => adjustableClock.Seek(pos); + Progress.RequestSeek = time => RequestSeek(time); ModDisplay.Current.BindTo(working.Mods); - - PlayerSettingsOverlay.PlaybackSettings.AdjustableClock = adjustableClock; } [BackgroundDependencyLoader(true)] diff --git a/osu.Game/Screens/Play/PausableGameplayContainer.cs b/osu.Game/Screens/Play/PausableGameplayContainer.cs index fa475deb34..99f0083b55 100644 --- a/osu.Game/Screens/Play/PausableGameplayContainer.cs +++ b/osu.Game/Screens/Play/PausableGameplayContainer.cs @@ -7,16 +7,13 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Timing; using osu.Game.Graphics; using osuTK.Graphics; namespace osu.Game.Screens.Play { /// - /// A container which handles pausing children, displaying a pause overlay with choices and processing the clock. - /// Exposes a to children via DI. - /// This alleviates a lot of the intricate pause logic from being in + /// A container which handles pausing children, displaying an overlay blocking its children during paused state. /// public class PausableGameplayContainer : Container { @@ -44,46 +41,33 @@ namespace osu.Game.Screens.Play public Action OnRetry; public Action OnQuit; - private readonly FramedClock offsetClock; - private readonly DecoupleableInterpolatingFramedClock adjustableClock; - - /// - /// The final clock which is exposed to underlying components. - /// - [Cached] - private readonly GameplayClock gameplayClock; + public Action Stop; + public Action Start; /// /// Creates a new . /// - /// The gameplay clock. This is the clock that will process frames. Includes user/system offsets. - /// The seekable clock. This is the clock that will be paused and resumed. Should not be processed (it is processed automatically by ). - public PausableGameplayContainer(FramedClock offsetClock, DecoupleableInterpolatingFramedClock adjustableClock) + public PausableGameplayContainer() { - this.offsetClock = offsetClock; - this.adjustableClock = adjustableClock; - - gameplayClock = new GameplayClock(offsetClock); - RelativeSizeAxes = Axes.Both; - AddInternal(content = new Container + InternalChildren = new[] { - Clock = this.offsetClock, - ProcessCustomClock = false, - RelativeSizeAxes = Axes.Both - }); - - AddInternal(pauseOverlay = new PauseOverlay - { - OnResume = () => + content = new Container { - IsResuming = true; - this.Delay(400).Schedule(Resume); + RelativeSizeAxes = Axes.Both }, - OnRetry = () => OnRetry(), - OnQuit = () => OnQuit(), - }); + pauseOverlay = new PauseOverlay + { + OnResume = () => + { + IsResuming = true; + this.Delay(400).Schedule(Resume); + }, + OnRetry = () => OnRetry(), + OnQuit = () => OnQuit(), + } + }; } public void Pause(bool force = false) => Schedule(() => // Scheduled to ensure a stable position in execution order, no matter how it was called. @@ -93,7 +77,7 @@ namespace osu.Game.Screens.Play if (IsPaused.Value) return; // stop the seekable clock (stops the audio eventually) - adjustableClock.Stop(); + Stop?.Invoke(); IsPaused.Value = true; pauseOverlay.Show(); @@ -105,14 +89,12 @@ namespace osu.Game.Screens.Play { if (!IsPaused.Value) return; - IsPaused.Value = false; IsResuming = false; lastPauseActionTime = Time.Current; - // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time - // This accounts for the audio clock source potentially taking time to enter a completely stopped state - adjustableClock.Seek(adjustableClock.CurrentTime); - adjustableClock.Start(); + IsPaused.Value = false; + + Start?.Invoke(); pauseOverlay.Hide(); } @@ -131,9 +113,6 @@ namespace osu.Game.Screens.Play if (!game.IsActive.Value && CanPause) Pause(); - if (!IsPaused.Value) - offsetClock.ProcessFrame(); - base.Update(); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 44707c74f5..429b9dda91 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -3,8 +3,6 @@ using System; using System.Linq; -using System.Threading.Tasks; -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -16,7 +14,6 @@ using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Framework.Threading; -using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Containers; @@ -53,7 +50,6 @@ namespace osu.Game.Screens.Play public bool AllowResults { get; set; } = true; private Bindable mouseWheelDisabled; - private Bindable userAudioOffset; private readonly Bindable storyboardReplacesBackground = new Bindable(); @@ -62,13 +58,6 @@ namespace osu.Game.Screens.Play public CursorContainer Cursor => RulesetContainer.Cursor; public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value; - private IAdjustableClock sourceClock; - - /// - /// The decoupled clock used for gameplay. Should be used for seeks and clock control. - /// - private DecoupleableInterpolatingFramedClock adjustableClock; - [Resolved] private ScoreManager scoreManager { get; set; } @@ -98,25 +87,117 @@ namespace osu.Game.Screens.Play public bool LoadedBeatmapSuccessfully => RulesetContainer?.Objects.Any() == true; + private GameplayClockContainer gameplayClockContainer; + [BackgroundDependencyLoader] private void load(AudioManager audio, APIAccess api, OsuConfigManager config) { this.api = api; - WorkingBeatmap working = Beatmap.Value; - if (working is DummyWorkingBeatmap) + WorkingBeatmap working = loadBeatmap(); + + if (working == null) return; sampleRestart = audio.Sample.Get(@"Gameplay/restart"); mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); - userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); - IBeatmap beatmap; + ScoreProcessor = RulesetContainer.CreateScoreProcessor(); + if (!ScoreProcessor.Mode.Disabled) + config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); + + InternalChild = gameplayClockContainer = new GameplayClockContainer(working, AllowLeadIn, RulesetContainer.GameplayStartTime); + + gameplayClockContainer.Children = new Drawable[] + { + PausableGameplayContainer = new PausableGameplayContainer + { + Retries = RestartCount, + OnRetry = restart, + OnQuit = performUserRequestedExit, + Start = gameplayClockContainer.Start, + Stop = gameplayClockContainer.Stop, + + CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, + Children = new Container[] + { + StoryboardContainer = CreateStoryboardContainer(), + new ScalingContainer(ScalingMode.Gameplay) + { + Child = new LocalSkinOverrideContainer(working.Skin) + { + RelativeSizeAxes = Axes.Both, + Child = RulesetContainer + } + }, + new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Breaks = working.Beatmap.Breaks + }, + new ScalingContainer(ScalingMode.Gameplay) + { + Child = RulesetContainer.Cursor?.CreateProxy() ?? new Container(), + }, + HUDOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working) + { + RequestSeek = gameplayClockContainer.Seek, + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }, + new SkipOverlay(RulesetContainer.GameplayStartTime) + { + RequestSeek = gameplayClockContainer.Seek + }, + } + }, + failOverlay = new FailOverlay + { + OnRetry = restart, + OnQuit = performUserRequestedExit, + }, + new HotkeyRetryOverlay + { + Action = () => + { + if (!this.IsCurrentScreen()) return; + + fadeOut(true); + restart(); + }, + } + }; + + // bind clock into components that require it + PausableGameplayContainer.IsPaused.BindTo(gameplayClockContainer.IsPaused); + RulesetContainer.IsPaused.BindTo(gameplayClockContainer.IsPaused); + HUDOverlay.PlayerSettingsOverlay.PlaybackSettings.UserPlaybackRate.BindTo(gameplayClockContainer.UserPlaybackRate); + + HUDOverlay.HoldToQuit.Action = performUserRequestedExit; + HUDOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); + + if (ShowStoryboard.Value) + initializeStoryboard(false); + + // Bind ScoreProcessor to ourselves + ScoreProcessor.AllJudged += onCompletion; + ScoreProcessor.Failed += onFail; + + foreach (var mod in Beatmap.Value.Mods.Value.OfType()) + mod.ApplyToScoreProcessor(ScoreProcessor); + } + + private WorkingBeatmap loadBeatmap() + { + WorkingBeatmap working = Beatmap.Value; + if (working is DummyWorkingBeatmap) + return null; try { - beatmap = working.Beatmap; + var beatmap = working.Beatmap; if (beatmap == null) throw new InvalidOperationException("Beatmap was not loaded"); @@ -140,119 +221,17 @@ namespace osu.Game.Screens.Play if (!RulesetContainer.Objects.Any()) { Logger.Log("Beatmap contains no hit objects!", level: LogLevel.Error); - return; + return null; } } catch (Exception e) { Logger.Error(e, "Could not load beatmap sucessfully!"); //couldn't load, hard abort! - return; + return null; } - sourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock(); - adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; - - adjustableClock.Seek(AllowLeadIn - ? Math.Min(0, RulesetContainer.GameplayStartTime - beatmap.BeatmapInfo.AudioLeadIn) - : RulesetContainer.GameplayStartTime); - - adjustableClock.ProcessFrame(); - - // Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited. - // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. - var platformOffsetClock = new FramedOffsetClock(adjustableClock) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 22 : 0 }; - - // the final usable gameplay clock with user-set offsets applied. - var offsetClock = new FramedOffsetClock(platformOffsetClock); - - userAudioOffset.ValueChanged += offset => offsetClock.Offset = offset.NewValue; - userAudioOffset.TriggerChange(); - - ScoreProcessor = RulesetContainer.CreateScoreProcessor(); - if (!ScoreProcessor.Mode.Disabled) - config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); - - InternalChildren = new Drawable[] - { - PausableGameplayContainer = new PausableGameplayContainer(offsetClock, adjustableClock) - { - Retries = RestartCount, - OnRetry = restart, - OnQuit = performUserRequestedExit, - CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, - Children = new Container[] - { - StoryboardContainer = CreateStoryboardContainer(), - new ScalingContainer(ScalingMode.Gameplay) - { - Child = new LocalSkinOverrideContainer(working.Skin) - { - RelativeSizeAxes = Axes.Both, - Child = RulesetContainer - } - }, - new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Breaks = beatmap.Breaks - }, - new ScalingContainer(ScalingMode.Gameplay) - { - Child = RulesetContainer.Cursor?.CreateProxy() ?? new Container(), - }, - HUDOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, adjustableClock) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, - new SkipOverlay(RulesetContainer.GameplayStartTime) - { - RequestSeek = time => adjustableClock.Seek(time) - }, - } - }, - failOverlay = new FailOverlay - { - OnRetry = restart, - OnQuit = performUserRequestedExit, - }, - new HotkeyRetryOverlay - { - Action = () => - { - if (!this.IsCurrentScreen()) return; - - fadeOut(true); - restart(); - }, - } - }; - - HUDOverlay.HoldToQuit.Action = performUserRequestedExit; - HUDOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); - - RulesetContainer.IsPaused.BindTo(PausableGameplayContainer.IsPaused); - - if (ShowStoryboard.Value) - initializeStoryboard(false); - - // Bind ScoreProcessor to ourselves - ScoreProcessor.AllJudged += onCompletion; - ScoreProcessor.Failed += onFail; - - foreach (var mod in Beatmap.Value.Mods.Value.OfType()) - mod.ApplyToScoreProcessor(ScoreProcessor); - } - - private void applyRateFromMods() - { - if (sourceClock == null) return; - - sourceClock.Rate = 1; - foreach (var mod in Beatmap.Value.Mods.Value.OfType()) - mod.ApplyToClock(sourceClock); + return working; } private void performUserRequestedExit() @@ -321,7 +300,7 @@ namespace osu.Game.Screens.Play if (Beatmap.Value.Mods.Value.OfType().Any(m => !m.AllowFail)) return false; - adjustableClock.Stop(); + gameplayClockContainer.Stop(); HasFailed = true; failOverlay.Retries = RestartCount; @@ -355,24 +334,7 @@ namespace osu.Game.Screens.Play storyboardReplacesBackground.Value = Beatmap.Value.Storyboard.ReplacesBackground && Beatmap.Value.Storyboard.HasDrawable; - Task.Run(() => - { - sourceClock.Reset(); - - Schedule(() => - { - adjustableClock.ChangeSource(sourceClock); - applyRateFromMods(); - - this.Delay(750).Schedule(() => - { - if (!PausableGameplayContainer.IsPaused.Value) - { - adjustableClock.Start(); - } - }); - }); - }); + gameplayClockContainer.Restart(); PausableGameplayContainer.Alpha = 0; PausableGameplayContainer.FadeIn(750, Easing.OutQuint); @@ -395,8 +357,8 @@ namespace osu.Game.Screens.Play if ((!AllowPause || HasFailed || !ValidForResume || PausableGameplayContainer?.IsPaused.Value != false || RulesetContainer?.HasReplayLoaded.Value != false) && (!PausableGameplayContainer?.IsResuming ?? true)) { - // In the case of replays, we may have changed the playback rate. - applyRateFromMods(); + gameplayClockContainer.ResetLocalAdjustments(); + fadeOut(); return base.OnExiting(next); } diff --git a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs index ebbed299f7..c691d161ed 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs @@ -4,7 +4,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Timing; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -16,7 +15,13 @@ namespace osu.Game.Screens.Play.PlayerSettings protected override string Title => @"playback"; - public IAdjustableClock AdjustableClock { set; get; } + public readonly Bindable UserPlaybackRate = new BindableDouble(1) + { + Default = 1, + MinValue = 0.5, + MaxValue = 2, + Precision = 0.1, + }; private readonly PlayerSliderBar rateSlider; @@ -47,31 +52,13 @@ namespace osu.Game.Screens.Play.PlayerSettings } }, }, - rateSlider = new PlayerSliderBar - { - Bindable = new BindableDouble(1) - { - Default = 1, - MinValue = 0.5, - MaxValue = 2, - Precision = 0.1, - }, - } + rateSlider = new PlayerSliderBar { Bindable = UserPlaybackRate } }; } protected override void LoadComplete() { base.LoadComplete(); - - if (AdjustableClock == null) - return; - - var clockRate = AdjustableClock.Rate; - - // can't trigger this line instantly as the underlying clock may not be ready to accept adjustments yet. - rateSlider.Bindable.ValueChanged += multiplier => AdjustableClock.Rate = clockRate * multiplier.NewValue; - rateSlider.Bindable.BindValueChanged(multiplier => multiplierText.Text = $"{multiplier.NewValue:0.0}x", true); } } From 64b6eaa84474b526fae71a09f7bc4c53d53e6948 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Mar 2019 12:16:17 +0900 Subject: [PATCH 11/21] Simplify inward bindings --- osu.Game/Screens/Play/Player.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 429b9dda91..50ecf5443a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -118,9 +118,10 @@ namespace osu.Game.Screens.Play OnQuit = performUserRequestedExit, Start = gameplayClockContainer.Start, Stop = gameplayClockContainer.Stop, + IsPaused = { BindTarget = gameplayClockContainer.IsPaused }, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, - Children = new Container[] + Children = new[] { StoryboardContainer = CreateStoryboardContainer(), new ScalingContainer(ScalingMode.Gameplay) @@ -137,12 +138,12 @@ namespace osu.Game.Screens.Play Origin = Anchor.Centre, Breaks = working.Beatmap.Breaks }, - new ScalingContainer(ScalingMode.Gameplay) - { - Child = RulesetContainer.Cursor?.CreateProxy() ?? new Container(), - }, + RulesetContainer.Cursor?.CreateProxy() ?? new Container(), HUDOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working) { + HoldToQuit = { Action = performUserRequestedExit }, + PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = gameplayClockContainer.UserPlaybackRate } } }, + KeyCounter = { Visible = { BindTarget = RulesetContainer.HasReplayLoaded } }, RequestSeek = gameplayClockContainer.Seek, Anchor = Anchor.Centre, Origin = Anchor.Centre @@ -171,12 +172,7 @@ namespace osu.Game.Screens.Play }; // bind clock into components that require it - PausableGameplayContainer.IsPaused.BindTo(gameplayClockContainer.IsPaused); RulesetContainer.IsPaused.BindTo(gameplayClockContainer.IsPaused); - HUDOverlay.PlayerSettingsOverlay.PlaybackSettings.UserPlaybackRate.BindTo(gameplayClockContainer.UserPlaybackRate); - - HUDOverlay.HoldToQuit.Action = performUserRequestedExit; - HUDOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); if (ShowStoryboard.Value) initializeStoryboard(false); From 50c1b3a576c0e1a86edd4b86cd1d6b6c47b561a5 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 7 Mar 2019 16:49:48 +0900 Subject: [PATCH 12/21] Move room resetting logic from MatchSubScreen to LoungeSubScreen --- osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs | 8 ++++++++ osu.Game/Screens/Multi/Match/MatchSubScreen.cs | 7 ------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index dd1e060125..7cbae611ea 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -107,6 +107,14 @@ namespace osu.Game.Screens.Multi.Lounge Filter.Search.HoldFocus = false; } + public override void OnResuming(IScreen last) + { + base.OnResuming(last); + + if (currentRoom.Value?.RoomID.Value == null) + currentRoom.Value = new Room(); + } + private void joinRequested(Room room) { processingOverlay.Show(); diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index 902a8c1c57..a71106872e 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -53,9 +53,6 @@ namespace osu.Game.Screens.Multi.Match private MatchLeaderboard leaderboard; - [Resolved] - private Bindable currentRoom { get; set; } - public MatchSubScreen(Room room) { Title = room.RoomID.Value == null ? "New room" : room.Name.Value; @@ -185,10 +182,6 @@ namespace osu.Game.Screens.Multi.Match public override bool OnExiting(IScreen next) { RoomManager?.PartRoom(); - - if (roomId.Value == null) - currentRoom.Value = new Room(); - return base.OnExiting(next); } From 11e5c6a2a0b4744184b7bcf169dd04e0f9d2f2b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Mar 2019 12:00:38 +0900 Subject: [PATCH 13/21] Fire initial APIStateChanged on local thread --- osu.Game/Online/API/APIAccess.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 4d039e0b8a..054c57ed75 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -70,13 +70,15 @@ namespace osu.Game.Online.API internal new void Schedule(Action action) => base.Schedule(action); + /// + /// Register a component to receive API events. + /// Fires once immediately to ensure correct . + /// + /// public void Register(IOnlineComponent component) { - Scheduler.Add(delegate - { - components.Add(component); - component.APIStateChanged(this, state); - }); + Scheduler.Add(delegate { components.Add(component); }); + component.APIStateChanged(this, state); } public void Unregister(IOnlineComponent component) From 075ea7012497269314808868c837d4bc181fe70e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Mar 2019 12:01:40 +0900 Subject: [PATCH 14/21] Move more toolbar to async load --- osu.Game/Overlays/Toolbar/Toolbar.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 61b2014af8..a159e21b7a 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Toolbar public Action OnHome; - private readonly ToolbarUserArea userArea; + private ToolbarUserArea userArea; protected override bool BlockPositionalInput => false; @@ -33,7 +33,8 @@ namespace osu.Game.Overlays.Toolbar private readonly Bindable overlayActivationMode = new Bindable(OverlayActivation.All); - public Toolbar() + [BackgroundDependencyLoader(true)] + private void load(OsuGame osuGame) { Children = new Drawable[] { @@ -78,11 +79,7 @@ namespace osu.Game.Overlays.Toolbar RelativeSizeAxes = Axes.X; Size = new Vector2(1, HEIGHT); - } - [BackgroundDependencyLoader(true)] - private void load(OsuGame osuGame) - { StateChanged += visibility => { if (overlayActivationMode.Value == OverlayActivation.Disabled) From 345c7f4fa813f19d0b3a97a442719ad930fdec1d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Mar 2019 12:30:52 +0900 Subject: [PATCH 15/21] Fix test regression --- osu.Game.Tests/Visual/TestCaseToolbar.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseToolbar.cs b/osu.Game.Tests/Visual/TestCaseToolbar.cs index be1b75823a..cb5f33911b 100644 --- a/osu.Game.Tests/Visual/TestCaseToolbar.cs +++ b/osu.Game.Tests/Visual/TestCaseToolbar.cs @@ -24,10 +24,13 @@ namespace osu.Game.Tests.Visual public TestCaseToolbar() { var toolbar = new Toolbar { State = Visibility.Visible }; + ToolbarNotificationButton notificationButton = null; - Add(toolbar); - - var notificationButton = toolbar.Children.OfType().Last().Children.OfType().First(); + AddStep("create toolbar", () => + { + Add(toolbar); + notificationButton = toolbar.Children.OfType().Last().Children.OfType().First(); + }); void setNotifications(int count) => AddStep($"set notification count to {count}", () => notificationButton.NotificationCount.Value = count); From 400514630dd33ffee37f579646ea675985167a7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Mar 2019 12:44:33 +0900 Subject: [PATCH 16/21] Fix incomplete comment --- osu.Game/Online/API/APIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 054c57ed75..5593abf348 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -72,7 +72,7 @@ namespace osu.Game.Online.API /// /// Register a component to receive API events. - /// Fires once immediately to ensure correct . + /// Fires once immediately to ensure a correct state. /// /// public void Register(IOnlineComponent component) From 2c98ba1c0c875cb0d3d6b031eacf8790a73bad5e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Mar 2019 14:59:45 +0900 Subject: [PATCH 17/21] Split out consumption and creation into two separate code paths --- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 10 ++++++++-- osu.Game/Rulesets/UI/Playfield.cs | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 47a064beee..51733c3c01 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Connections; using osu.Game.Rulesets.UI; using System.Linq; +using osu.Framework.Graphics.Cursor; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.UI.Cursor; @@ -23,6 +24,12 @@ namespace osu.Game.Rulesets.Osu.UI public static readonly Vector2 BASE_SIZE = new Vector2(512, 384); + private readonly PlayfieldAdjustmentContainer adjustmentContainer; + + protected override Container CursorTargetContainer => adjustmentContainer; + + protected override CursorContainer CreateCursor() => new GameplayCursorContainer(); + public OsuPlayfield() { Anchor = Anchor.Centre; @@ -30,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.UI Size = new Vector2(0.75f); - InternalChild = new PlayfieldAdjustmentContainer + InternalChild = adjustmentContainer = new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] @@ -51,7 +58,6 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, Depth = -1, }, - Cursor = new GameplayCursorContainer(), } }; } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index f0c2b8859c..2179196d60 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -56,6 +56,10 @@ namespace osu.Game.Rulesets.UI RelativeSizeAxes = Axes.Both; hitObjectContainerLazy = new Lazy(CreateHitObjectContainer); + + Cursor = CreateCursor(); + if (Cursor != null) + CursorTargetContainer.Add(Cursor); } private WorkingBeatmap beatmap; @@ -86,7 +90,19 @@ namespace osu.Game.Rulesets.UI /// /// The cursor currently being used by this . May be null if no cursor is provided. /// - public CursorContainer Cursor { get; protected set; } + public CursorContainer Cursor { get; private set; } + + /// + /// Provide an optional cursor which is to be used for gameplay. + /// If providing a cursor, must also point to a valid target container. + /// + /// The cursor, or null if a cursor is not rqeuired. + protected virtual CursorContainer CreateCursor() => null; + + /// + /// The target container to add the cursor after it is created. + /// + protected virtual Container CursorTargetContainer => null; /// /// Registers a as a nested . From a73e3d9700949d85608dbeb2d00e21a920dacecc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Mar 2019 15:01:45 +0900 Subject: [PATCH 18/21] Move cursor construction to BDL --- osu.Game/Rulesets/UI/Playfield.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 2179196d60..78d14a27e3 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -56,10 +56,6 @@ namespace osu.Game.Rulesets.UI RelativeSizeAxes = Axes.Both; hitObjectContainerLazy = new Lazy(CreateHitObjectContainer); - - Cursor = CreateCursor(); - if (Cursor != null) - CursorTargetContainer.Add(Cursor); } private WorkingBeatmap beatmap; @@ -68,6 +64,10 @@ namespace osu.Game.Rulesets.UI private void load(IBindable beatmap) { this.beatmap = beatmap.Value; + + Cursor = CreateCursor(); + if (Cursor != null) + CursorTargetContainer.Add(Cursor); } /// From 42efea1e06ff2381016107692ec43dcabf920157 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Mar 2019 15:05:45 +0900 Subject: [PATCH 19/21] Apply review --- .../Screens/Play/GameplayClockContainer.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index f769bfd326..594df63420 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Screens.Play { /// - /// Manages the various intricacies of the gameplay clock. + /// Encapsulates gameplay timing logic and provides a for children. /// public class GameplayClockContainer : Container { @@ -35,12 +35,6 @@ namespace osu.Game.Screens.Play /// private readonly DecoupleableInterpolatingFramedClock adjustableClock; - /// - /// The final clock which is exposed to underlying components. - /// - [Cached] - private readonly GameplayClock gameplayClock; - public readonly Bindable UserPlaybackRate = new BindableDouble(1) { Default = 1, @@ -49,16 +43,22 @@ namespace osu.Game.Screens.Play Precision = 0.1, }; + /// + /// The final clock which is exposed to underlying components. + /// + [Cached] + private readonly GameplayClock gameplayClock; + private Bindable userAudioOffset; private readonly FramedOffsetClock offsetClock; public GameplayClockContainer(WorkingBeatmap beatmap, bool allowLeadIn, double gameplayStartTime) { - RelativeSizeAxes = Axes.Both; - this.beatmap = beatmap; + RelativeSizeAxes = Axes.Both; + sourceClock = (IAdjustableClock)beatmap.Track ?? new StopwatchClock(); adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; From 09b5cf48911c66db9a0d3866c5e082bfd3d9f0ec Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Mar 2019 15:14:07 +0900 Subject: [PATCH 20/21] Move sizing to ctor --- osu.Game/Overlays/Toolbar/Toolbar.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index a159e21b7a..dca0226499 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -33,6 +33,12 @@ namespace osu.Game.Overlays.Toolbar private readonly Bindable overlayActivationMode = new Bindable(OverlayActivation.All); + public Toolbar() + { + RelativeSizeAxes = Axes.X; + Size = new Vector2(1, HEIGHT); + } + [BackgroundDependencyLoader(true)] private void load(OsuGame osuGame) { @@ -77,9 +83,6 @@ namespace osu.Game.Overlays.Toolbar } }; - RelativeSizeAxes = Axes.X; - Size = new Vector2(1, HEIGHT); - StateChanged += visibility => { if (overlayActivationMode.Value == OverlayActivation.Disabled) From d055b248ac4b04c39100d4c0fe386af45a67a782 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Mar 2019 15:56:36 +0900 Subject: [PATCH 21/21] Remove blank line --- osu.Game/Screens/Play/Player.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c0f4eee895..ced0a43679 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -114,7 +114,6 @@ namespace osu.Game.Screens.Play Start = gameplayClockContainer.Start, Stop = gameplayClockContainer.Stop, IsPaused = { BindTarget = gameplayClockContainer.IsPaused }, - CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, Children = new[] {