From 2e242075b486692326ad6efe0fc7e7ed97750e60 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 29 Jul 2019 14:30:46 +0900 Subject: [PATCH 001/966] Remove and re-add backbutton instead and add tests --- .../Visual/Menus/TestSceneExitingScreens.cs | 152 ++++++++++++++++++ .../Input/Bindings/GlobalActionContainer.cs | 29 +++- osu.Game/OsuGame.cs | 33 ++-- 3 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs diff --git a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs new file mode 100644 index 0000000000..fafaa3a397 --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs @@ -0,0 +1,152 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Platform; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Mods; +using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; +using osuTK.Graphics; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Menus +{ + public class TestSceneExitingScreens : ManualInputManagerTestScene + { + private readonly TestOsuGame osuGame = new TestOsuGame(); + + [BackgroundDependencyLoader] + private void load(GameHost gameHost) + { + osuGame.SetHost(gameHost); + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + osuGame + }; + } + + [SetUpSteps] + public void SetUpSteps() + { + AddUntilStep("wait for load", () => osuGame.IsLoaded); + AddUntilStep("wait for main menu", () => + { + var current = osuGame.ScreenStack?.CurrentScreen; + + switch (current) + { + case null: + case Intro _: + case Disclaimer _: + return false; + + case MainMenu _: + return true; + + default: + current.Exit(); + return false; + } + }); + } + + [Test] + public void TestExitingSongSelectWithEscape() + { + TestSongSelect songSelect = null; + + AddStep("Push songselect", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); + AddUntilStep("Wait for song select", () => songSelect.IsCurrentScreen()); + AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); + AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); + AddStep("Press escape", () => pressAndRelease(Key.Escape)); + AddAssert("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden); + exitViaEscapeAndConfirm(); + } + + [Test] + public void TestExitingSongSelectWithClick() + { + TestSongSelect songSelect = null; + + AddStep("Push songselect", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); + AddUntilStep("Wait for song select", () => songSelect.IsCurrentScreen()); + AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); + AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); + AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(osuGame.BackButton)); + + // BackButton handles hover using its child button, so this checks whether or not any of BackButton's children are hovered. + AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == osuGame.BackButton)); + + AddStep("Click back button", () => InputManager.Click(MouseButton.Left)); + AddAssert("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden); + exitViaBackButtonAndConfirm(); + } + + [Test] + public void TestExitMultiWithEscape() + { + Screens.Multi.Multiplayer multiplayer = null; + + AddStep("Push songselect", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); + AddUntilStep("Wait for song select", () => multiplayer.IsCurrentScreen()); + exitViaEscapeAndConfirm(); + } + + [Test] + public void TestExitMultiWithBackButton() + { + Screens.Multi.Multiplayer multiplayer = null; + + AddStep("Push songselect", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); + AddUntilStep("Wait for song select", () => multiplayer.IsCurrentScreen()); + + exitViaBackButtonAndConfirm(); + } + + private void exitViaEscapeAndConfirm() + { + AddStep("Press escape", () => pressAndRelease(Key.Escape)); + AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); + } + + private void exitViaBackButtonAndConfirm() + { + AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(osuGame.BackButton)); + AddStep("Click back button", () => InputManager.Click(MouseButton.Left)); + AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); + } + + private void pressAndRelease(Key key) + { + InputManager.PressKey(key); + InputManager.ReleaseKey(key); + } + + private class TestOsuGame : OsuGame + { + public new ScreenStack ScreenStack => base.ScreenStack; + + public new BackButton BackButton => base.BackButton; + } + + private class TestSongSelect : PlaySongSelect + { + public ModSelectOverlay ModSelectOverlay => ModSelect; + } + } +} diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 669fd62e45..373333696a 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Input.Bindings { @@ -55,8 +56,32 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed), }; - protected override IEnumerable KeyBindingInputQueue => - handler == null ? base.KeyBindingInputQueue : base.KeyBindingInputQueue.Prepend(handler); + protected override IEnumerable KeyBindingInputQueue + { + get + { + var queue = base.KeyBindingInputQueue.ToList(); + + if (handler != null) + yield return handler; + + BackButton backButton = null; + + foreach (var drawable in queue) + { + if (drawable is BackButton button) + { + backButton = button; + continue; + } + + yield return drawable; + } + + if (backButton != null) + yield return backButton; + } + } } public enum GlobalAction diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ceaf0c3d5e..64958c9a09 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -81,10 +81,11 @@ namespace osu.Game public readonly Bindable OverlayActivationMode = new Bindable(); - private OsuScreenStack screenStack; + protected OsuScreenStack ScreenStack; + protected BackButton BackButton; + private VolumeOverlay volume; private OsuLogo osuLogo; - private BackButton backButton; private MainMenu menuScreen; private Intro introScreen; @@ -325,7 +326,7 @@ namespace osu.Game performFromMainMenuTask?.Cancel(); // if the current screen does not allow screen changing, give the user an option to try again later. - if (!bypassScreenAllowChecks && (screenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange == false) + if (!bypassScreenAllowChecks && (ScreenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange == false) { notifications.Post(new SimpleNotification { @@ -343,7 +344,7 @@ namespace osu.Game CloseAllOverlays(false); // we may already be at the target screen type. - if (targetScreen != null && screenStack.CurrentScreen?.GetType() == targetScreen) + if (targetScreen != null && ScreenStack.CurrentScreen?.GetType() == targetScreen) { action(); return; @@ -406,15 +407,15 @@ namespace osu.Game RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }, - backButton = new BackButton + ScreenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }, + BackButton = new BackButton { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Action = () => { - if ((screenStack.CurrentScreen as IOsuScreen)?.AllowBackButton == true) - screenStack.Exit(); + if ((ScreenStack.CurrentScreen as IOsuScreen)?.AllowBackButton == true) + ScreenStack.Exit(); } }, logoContainer = new Container { RelativeSizeAxes = Axes.Both }, @@ -427,15 +428,15 @@ namespace osu.Game idleTracker }); - screenStack.ScreenPushed += screenPushed; - screenStack.ScreenExited += screenExited; + ScreenStack.ScreenPushed += screenPushed; + ScreenStack.ScreenExited += screenExited; loadComponentSingleFile(osuLogo, logo => { logoContainer.Add(logo); // Loader has to be created after the logo has finished loading as Loader performs logo transformations on entering. - screenStack.Push(new Loader + ScreenStack.Push(new Loader { RelativeSizeAxes = Axes.Both }); @@ -755,13 +756,13 @@ namespace osu.Game protected override bool OnExiting() { - if (screenStack.CurrentScreen is Loader) + if (ScreenStack.CurrentScreen is Loader) return false; if (introScreen == null) return true; - if (!introScreen.DidLoadMenu || !(screenStack.CurrentScreen is Intro)) + if (!introScreen.DidLoadMenu || !(ScreenStack.CurrentScreen is Intro)) { Scheduler.Add(introScreen.MakeCurrent); return true; @@ -789,7 +790,7 @@ namespace osu.Game screenContainer.Padding = new MarginPadding { Top = ToolbarOffset }; overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; - MenuCursorContainer.CanShowCursor = (screenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false; + MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false; } protected virtual void ScreenChanged(IScreen current, IScreen newScreen) @@ -815,9 +816,9 @@ namespace osu.Game Toolbar.Show(); if (newOsuScreen.AllowBackButton) - backButton.Show(); + BackButton.Show(); else - backButton.Hide(); + BackButton.Hide(); } } From 8742ed8a9cc5768c89f9b3d2230c0f3ca74abd1c Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 29 Jul 2019 17:23:45 +0900 Subject: [PATCH 002/966] Fix step names --- .../Visual/Menus/TestSceneExitingScreens.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs index fafaa3a397..377d7b60fb 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Menus AddUntilStep("wait for load", () => osuGame.IsLoaded); AddUntilStep("wait for main menu", () => { - var current = osuGame.ScreenStack?.CurrentScreen; + var current = osuGame.ScreenStack.CurrentScreen; switch (current) { @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Menus { TestSongSelect songSelect = null; - AddStep("Push songselect", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); + AddStep("Push song select", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); AddUntilStep("Wait for song select", () => songSelect.IsCurrentScreen()); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); @@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.Menus { TestSongSelect songSelect = null; - AddStep("Push songselect", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); + AddStep("Push song select", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); AddUntilStep("Wait for song select", () => songSelect.IsCurrentScreen()); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); @@ -102,8 +102,8 @@ namespace osu.Game.Tests.Visual.Menus { Screens.Multi.Multiplayer multiplayer = null; - AddStep("Push songselect", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); - AddUntilStep("Wait for song select", () => multiplayer.IsCurrentScreen()); + AddStep("Push multiplayer", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); + AddUntilStep("Wait for multiplayer", () => multiplayer.IsCurrentScreen()); exitViaEscapeAndConfirm(); } @@ -112,8 +112,8 @@ namespace osu.Game.Tests.Visual.Menus { Screens.Multi.Multiplayer multiplayer = null; - AddStep("Push songselect", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); - AddUntilStep("Wait for song select", () => multiplayer.IsCurrentScreen()); + AddStep("Push multiplayer", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); + AddUntilStep("Wait for multiplayer", () => multiplayer.IsCurrentScreen()); exitViaBackButtonAndConfirm(); } From e8c039bb8a7d6fb5babe3628f1fd898402194969 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 29 Jul 2019 18:45:16 +0900 Subject: [PATCH 003/966] Use a receptor model instead --- .../UserInterface/TestSceneBackButton.cs | 4 +- osu.Game/Graphics/UserInterface/BackButton.cs | 38 +++++++++++-------- .../Input/Bindings/GlobalActionContainer.cs | 29 +------------- osu.Game/OsuGame.cs | 5 ++- 4 files changed, 32 insertions(+), 44 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs index 38a9af05d8..05d14abe30 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs @@ -22,6 +22,7 @@ namespace osu.Game.Tests.Visual.UserInterface public TestSceneBackButton() { BackButton button; + BackButton.BackButtonReceptor receptor = new BackButton.BackButtonReceptor(); Child = new Container { @@ -31,12 +32,13 @@ namespace osu.Game.Tests.Visual.UserInterface Masking = true, Children = new Drawable[] { + receptor, new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, - button = new BackButton + button = new BackButton(receptor) { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index 48bf0848ae..fe82a5d8e2 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -10,14 +10,16 @@ using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface { - public class BackButton : VisibilityContainer, IKeyBindingHandler + public class BackButton : VisibilityContainer { public Action Action; private readonly TwoLayerButton button; - public BackButton() + public BackButton(BackButtonReceptor receptor) { + receptor.OnBackPressed += () => Action.Invoke(); + Size = TwoLayerButton.SIZE_EXTENDED; Child = button = new TwoLayerButton @@ -37,19 +39,6 @@ namespace osu.Game.Graphics.UserInterface button.HoverColour = colours.PinkDark; } - public bool OnPressed(GlobalAction action) - { - if (action == GlobalAction.Back) - { - Action?.Invoke(); - return true; - } - - return false; - } - - public bool OnReleased(GlobalAction action) => action == GlobalAction.Back; - protected override void PopIn() { button.MoveToX(0, 400, Easing.OutQuint); @@ -61,5 +50,24 @@ namespace osu.Game.Graphics.UserInterface button.MoveToX(-TwoLayerButton.SIZE_EXTENDED.X / 2, 400, Easing.OutQuint); button.FadeOut(400, Easing.OutQuint); } + + public class BackButtonReceptor : Drawable, IKeyBindingHandler + { + public Action OnBackPressed; + + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.Back: + OnBackPressed.Invoke(); + return true; + } + + return false; + } + + public bool OnReleased(GlobalAction action) => action == GlobalAction.Back; + } } } diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 373333696a..669fd62e45 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -7,7 +7,6 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Input.Bindings { @@ -56,32 +55,8 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed), }; - protected override IEnumerable KeyBindingInputQueue - { - get - { - var queue = base.KeyBindingInputQueue.ToList(); - - if (handler != null) - yield return handler; - - BackButton backButton = null; - - foreach (var drawable in queue) - { - if (drawable is BackButton button) - { - backButton = button; - continue; - } - - yield return drawable; - } - - if (backButton != null) - yield return backButton; - } - } + protected override IEnumerable KeyBindingInputQueue => + handler == null ? base.KeyBindingInputQueue : base.KeyBindingInputQueue.Prepend(handler); } public enum GlobalAction diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 64958c9a09..3018cea276 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -84,6 +84,8 @@ namespace osu.Game protected OsuScreenStack ScreenStack; protected BackButton BackButton; + private BackButton.BackButtonReceptor backButtonReceptor; + private VolumeOverlay volume; private OsuLogo osuLogo; @@ -407,8 +409,9 @@ namespace osu.Game RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + backButtonReceptor = new BackButton.BackButtonReceptor(), ScreenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }, - BackButton = new BackButton + BackButton = new BackButton(backButtonReceptor) { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, From 6d1203a5993a0faec79e1ba4076522e11acc9cba Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 30 Jul 2019 12:00:04 +0900 Subject: [PATCH 004/966] Move screen pushes into function, rename receptor --- .../Visual/Menus/TestSceneExitingScreens.cs | 27 +++++++++---------- .../UserInterface/TestSceneBackButton.cs | 2 +- osu.Game/Graphics/UserInterface/BackButton.cs | 6 ++--- osu.Game/OsuGame.cs | 7 +++-- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs index 377d7b60fb..4780111e66 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs @@ -1,6 +1,7 @@ // 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 NUnit.Framework; using osu.Framework.Allocation; @@ -43,7 +44,7 @@ namespace osu.Game.Tests.Visual.Menus public void SetUpSteps() { AddUntilStep("wait for load", () => osuGame.IsLoaded); - AddUntilStep("wait for main menu", () => + AddUntilStep("exit to main menu", () => { var current = osuGame.ScreenStack.CurrentScreen; @@ -69,8 +70,7 @@ namespace osu.Game.Tests.Visual.Menus { TestSongSelect songSelect = null; - AddStep("Push song select", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); - AddUntilStep("Wait for song select", () => songSelect.IsCurrentScreen()); + pushAndConfirm(() => songSelect = new TestSongSelect(), "song select"); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); AddStep("Press escape", () => pressAndRelease(Key.Escape)); @@ -83,8 +83,7 @@ namespace osu.Game.Tests.Visual.Menus { TestSongSelect songSelect = null; - AddStep("Push song select", () => osuGame.ScreenStack.Push(songSelect = new TestSongSelect())); - AddUntilStep("Wait for song select", () => songSelect.IsCurrentScreen()); + pushAndConfirm(() => songSelect = new TestSongSelect(), "song select"); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(osuGame.BackButton)); @@ -100,24 +99,24 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestExitMultiWithEscape() { - Screens.Multi.Multiplayer multiplayer = null; - - AddStep("Push multiplayer", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); - AddUntilStep("Wait for multiplayer", () => multiplayer.IsCurrentScreen()); + pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - Screens.Multi.Multiplayer multiplayer = null; - - AddStep("Push multiplayer", () => osuGame.ScreenStack.Push(multiplayer = new Screens.Multi.Multiplayer())); - AddUntilStep("Wait for multiplayer", () => multiplayer.IsCurrentScreen()); - + pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); exitViaBackButtonAndConfirm(); } + private void pushAndConfirm(Func newScreen, string screenName) + { + Screen screen = null; + AddStep($"Push new {screenName}", () => osuGame.ScreenStack.Push(screen = newScreen())); + AddUntilStep($"Wait for new {screenName}", () => screen.IsCurrentScreen()); + } + private void exitViaEscapeAndConfirm() { AddStep("Press escape", () => pressAndRelease(Key.Escape)); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs index 05d14abe30..b7d7053dcd 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs @@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.UserInterface public TestSceneBackButton() { BackButton button; - BackButton.BackButtonReceptor receptor = new BackButton.BackButtonReceptor(); + BackButton.Receptor receptor = new BackButton.Receptor(); Child = new Container { diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index fe82a5d8e2..9808eda4df 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -16,9 +16,9 @@ namespace osu.Game.Graphics.UserInterface private readonly TwoLayerButton button; - public BackButton(BackButtonReceptor receptor) + public BackButton(Receptor receptor) { - receptor.OnBackPressed += () => Action.Invoke(); + receptor.OnBackPressed = () => Action.Invoke(); Size = TwoLayerButton.SIZE_EXTENDED; @@ -51,7 +51,7 @@ namespace osu.Game.Graphics.UserInterface button.FadeOut(400, Easing.OutQuint); } - public class BackButtonReceptor : Drawable, IKeyBindingHandler + public class Receptor : Drawable, IKeyBindingHandler { public Action OnBackPressed; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 3018cea276..a889af94eb 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -84,8 +84,6 @@ namespace osu.Game protected OsuScreenStack ScreenStack; protected BackButton BackButton; - private BackButton.BackButtonReceptor backButtonReceptor; - private VolumeOverlay volume; private OsuLogo osuLogo; @@ -393,6 +391,7 @@ namespace osu.Game ScoreManager.PresentImport = items => PresentScore(items.First()); Container logoContainer; + BackButton.Receptor receptor; dependencies.CacheAs(idleTracker = new GameIdleTracker(6000)); @@ -409,9 +408,9 @@ namespace osu.Game RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - backButtonReceptor = new BackButton.BackButtonReceptor(), + receptor = new BackButton.Receptor(), ScreenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }, - BackButton = new BackButton(backButtonReceptor) + BackButton = new BackButton(receptor) { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, From 9e809a2342797ca55fbee818da5a7f98809b9cc1 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 30 Jul 2019 12:05:29 +0900 Subject: [PATCH 005/966] fix merge --- osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs index 4780111e66..f89e67db74 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs @@ -51,7 +51,7 @@ namespace osu.Game.Tests.Visual.Menus switch (current) { case null: - case Intro _: + case IntroScreen _: case Disclaimer _: return false; From 82fcb88f5c7e7cc5584ba3ffcb57ddca78d43bbd Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 30 Jul 2019 12:11:08 +0900 Subject: [PATCH 006/966] update names --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4223184a68..77f16549fe 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -765,7 +765,7 @@ namespace osu.Game if (introScreen == null) return true; - if (!introScreen.DidLoadMenu || !(screenStack.CurrentScreen is IntroScreen)) + if (!introScreen.DidLoadMenu || !(ScreenStack.CurrentScreen is IntroScreen)) { Scheduler.Add(introScreen.MakeCurrent); return true; From 98bb6da9756940cf7ae89ec02ad11c880271087e Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 30 Jul 2019 18:16:17 +0900 Subject: [PATCH 007/966] rename test scene and create a new game each test --- ...creens.cs => TestSceneScreenNavigation.cs} | 40 +++++++------------ 1 file changed, 14 insertions(+), 26 deletions(-) rename osu.Game.Tests/Visual/Menus/{TestSceneExitingScreens.cs => TestSceneScreenNavigation.cs} (81%) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs similarity index 81% rename from osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs rename to osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index f89e67db74..e77a7a83c3 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneExitingScreens.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -20,49 +20,37 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Menus { - public class TestSceneExitingScreens : ManualInputManagerTestScene + public class TestSceneScreenNavigation : ManualInputManagerTestScene { - private readonly TestOsuGame osuGame = new TestOsuGame(); + private GameHost gameHost; + private TestOsuGame osuGame; [BackgroundDependencyLoader] private void load(GameHost gameHost) { - osuGame.SetHost(gameHost); + this.gameHost = gameHost; - Children = new Drawable[] + Child = new Box { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - osuGame + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, }; } [SetUpSteps] public void SetUpSteps() { - AddUntilStep("wait for load", () => osuGame.IsLoaded); - AddUntilStep("exit to main menu", () => + AddStep("Create new game instance", () => { - var current = osuGame.ScreenStack.CurrentScreen; + if (osuGame != null) + Remove(osuGame); - switch (current) - { - case null: - case IntroScreen _: - case Disclaimer _: - return false; + osuGame = new TestOsuGame(); + osuGame.SetHost(gameHost); - case MainMenu _: - return true; - - default: - current.Exit(); - return false; - } + Add(osuGame); }); + AddUntilStep("wait for load and menu is current", () => osuGame.IsLoaded && osuGame.ScreenStack.CurrentScreen is MainMenu); } [Test] From 0291a708d45f38c6ae85dc45fe8c9055ed12ceed Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 30 Jul 2019 18:18:03 +0900 Subject: [PATCH 008/966] fix step name and rename test --- osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index e77a7a83c3..ca94f2b636 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -50,11 +50,11 @@ namespace osu.Game.Tests.Visual.Menus Add(osuGame); }); - AddUntilStep("wait for load and menu is current", () => osuGame.IsLoaded && osuGame.ScreenStack.CurrentScreen is MainMenu); + AddUntilStep("Wait for main menu", () => osuGame.IsLoaded && osuGame.ScreenStack.CurrentScreen is MainMenu); } [Test] - public void TestExitingSongSelectWithEscape() + public void TestExitSongSelectWithEscape() { TestSongSelect songSelect = null; @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Menus } [Test] - public void TestExitingSongSelectWithClick() + public void TestExitSongSelectWithClick() { TestSongSelect songSelect = null; From 5aece2d5f2c718be42c1b5805e37efa381f18e0d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 31 Jul 2019 16:03:05 +0900 Subject: [PATCH 009/966] fix tests --- .../Visual/Menus/TestSceneScreenNavigation.cs | 23 ++++++++++++++++--- osu.Game/OsuGame.cs | 7 +++--- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index ca94f2b636..de6daf9618 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -13,8 +13,10 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; +using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Select; +using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -25,6 +27,8 @@ namespace osu.Game.Tests.Visual.Menus private GameHost gameHost; private TestOsuGame osuGame; + private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(0, osuGame.LayoutRectangle.Bottom)); + [BackgroundDependencyLoader] private void load(GameHost gameHost) { @@ -50,7 +54,8 @@ namespace osu.Game.Tests.Visual.Menus Add(osuGame); }); - AddUntilStep("Wait for main menu", () => osuGame.IsLoaded && osuGame.ScreenStack.CurrentScreen is MainMenu); + AddUntilStep("Wait for load", () => osuGame.IsLoaded); + AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); } [Test] @@ -80,7 +85,7 @@ namespace osu.Game.Tests.Visual.Menus AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == osuGame.BackButton)); AddStep("Click back button", () => InputManager.Click(MouseButton.Left)); - AddAssert("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden); + AddUntilStep("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden); exitViaBackButtonAndConfirm(); } @@ -102,7 +107,7 @@ namespace osu.Game.Tests.Visual.Menus { Screen screen = null; AddStep($"Push new {screenName}", () => osuGame.ScreenStack.Push(screen = newScreen())); - AddUntilStep($"Wait for new {screenName}", () => screen.IsCurrentScreen()); + AddUntilStep($"Wait for new {screenName}", () => osuGame.ScreenStack.CurrentScreen == screen); } private void exitViaEscapeAndConfirm() @@ -129,11 +134,23 @@ namespace osu.Game.Tests.Visual.Menus public new ScreenStack ScreenStack => base.ScreenStack; public new BackButton BackButton => base.BackButton; + + protected override Loader CreateLoader() => new TestLoader(); } private class TestSongSelect : PlaySongSelect { public ModSelectOverlay ModSelectOverlay => ModSelect; } + + private class TestLoader : Loader + { + protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(); + + private class TestShaderPrecompiler : ShaderPrecompiler + { + protected override bool AllLoaded => true; + } + } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 77f16549fe..6d85623eb9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -105,6 +105,8 @@ namespace osu.Game private readonly List visibleBlockingOverlays = new List(); + protected virtual Loader CreateLoader() => new Loader(); + public OsuGame(string[] args = null) { this.args = args; @@ -439,10 +441,7 @@ namespace osu.Game logoContainer.Add(logo); // Loader has to be created after the logo has finished loading as Loader performs logo transformations on entering. - ScreenStack.Push(new Loader - { - RelativeSizeAxes = Axes.Both - }); + ScreenStack.Push(CreateLoader().With(l => l.RelativeSizeAxes = Axes.Both)); }); loadComponentSingleFile(Toolbar = new Toolbar diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 1a3e1213b4..e9eab12557 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -316,7 +316,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction = Scheduler.AddDelayed(() => { if (impact) - logo.Impact(); + logo?.Impact(); game?.Toolbar.Show(); }, 200); From 980686f6bff6a0bc3f7da03d7826e3a7b46806d7 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 31 Jul 2019 19:30:35 +0900 Subject: [PATCH 010/966] get tests running again --- .../Visual/Menus/TestSceneScreenNavigation.cs | 34 ++++++++++++++----- osu.Game/OsuGame.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- osu.Game/Screens/Multi/Multiplayer.cs | 4 ++- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index de6daf9618..b4c7716e37 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -5,17 +5,23 @@ using System; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; +using osu.Game.Rulesets; using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Select; +using osu.Game.Tests.Resources; using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -27,7 +33,7 @@ namespace osu.Game.Tests.Visual.Menus private GameHost gameHost; private TestOsuGame osuGame; - private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(0, osuGame.LayoutRectangle.Bottom)); + private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(25, osuGame.LayoutRectangle.Bottom - 25)); [BackgroundDependencyLoader] private void load(GameHost gameHost) @@ -55,7 +61,8 @@ namespace osu.Game.Tests.Visual.Menus Add(osuGame); }); AddUntilStep("Wait for load", () => osuGame.IsLoaded); - AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); + AddUntilStep("Wait for intro", () => osuGame.ScreenStack.CurrentScreen is IntroScreen); + AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded); } [Test] @@ -79,7 +86,7 @@ namespace osu.Game.Tests.Visual.Menus pushAndConfirm(() => songSelect = new TestSongSelect(), "song select"); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); - AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(osuGame.BackButton)); + AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition)); // BackButton handles hover using its child button, so this checks whether or not any of BackButton's children are hovered. AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == osuGame.BackButton)); @@ -92,22 +99,28 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestExitMultiWithEscape() { - pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); + pushAndConfirm(() => new TestMultiplayer(), "multiplayer"); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); + pushAndConfirm(() => new TestMultiplayer(), "multiplayer"); exitViaBackButtonAndConfirm(); } private void pushAndConfirm(Func newScreen, string screenName) { Screen screen = null; - AddStep($"Push new {screenName}", () => osuGame.ScreenStack.Push(screen = newScreen())); - AddUntilStep($"Wait for new {screenName}", () => osuGame.ScreenStack.CurrentScreen == screen); + AddStep($"Push new {screenName}", () => + { + if (screenName == "song select") + Logger.Log("fuck"); + + osuGame.ScreenStack.Push(screen = newScreen()); + }); + AddUntilStep($"Wait for new {screenName}", () => osuGame.ScreenStack.CurrentScreen == screen && screen.IsLoaded); } private void exitViaEscapeAndConfirm() @@ -118,7 +131,7 @@ namespace osu.Game.Tests.Visual.Menus private void exitViaBackButtonAndConfirm() { - AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(osuGame.BackButton)); + AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition)); AddStep("Click back button", () => InputManager.Click(MouseButton.Left)); AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); } @@ -143,6 +156,11 @@ namespace osu.Game.Tests.Visual.Menus public ModSelectOverlay ModSelectOverlay => ModSelect; } + private class TestMultiplayer : Screens.Multi.Multiplayer + { + protected override bool RequireOnline => false; + } + private class TestLoader : Loader { protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 38b9526364..9fa1eb8aa7 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -317,7 +317,7 @@ namespace osu.Game private void currentTrackCompleted() { - if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled) + if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled && musicController.IsLoaded) musicController.NextTrack(); } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index e9eab12557..1a3e1213b4 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -316,7 +316,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction = Scheduler.AddDelayed(() => { if (impact) - logo?.Impact(); + logo.Impact(); game?.Toolbar.Show(); }, 200); diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 90806bab6e..3d9997e236 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -34,6 +34,8 @@ namespace osu.Game.Screens.Multi public override bool DisallowExternalBeatmapRulesetChanges => true; + protected virtual bool RequireOnline => true; + private readonly MultiplayerWaveContainer waves; private readonly OsuButton createButton; @@ -166,7 +168,7 @@ namespace osu.Game.Screens.Multi public void APIStateChanged(IAPIProvider api, APIState state) { - if (state != APIState.Online) + if (RequireOnline && state != APIState.Online) forcefullyExit(); } From 351b6e6259769bd98384142ebf9f6d1713a80760 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 31 Jul 2019 19:47:41 +0900 Subject: [PATCH 011/966] Add new options test --- .../Visual/Menus/TestSceneScreenNavigation.cs | 23 ++++++++++++++----- osu.Game/OsuGame.cs | 15 ++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index b4c7716e37..f71e8dc2ce 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -5,7 +5,6 @@ using System; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -13,15 +12,12 @@ using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using osu.Game.Overlays.Mods; -using osu.Game.Rulesets; using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Select; -using osu.Game.Tests.Resources; using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -35,6 +31,8 @@ namespace osu.Game.Tests.Visual.Menus private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(25, osuGame.LayoutRectangle.Bottom - 25)); + private Vector2 optionsButtonPosition => osuGame.ToScreenSpace(new Vector2(25, 25)); + [BackgroundDependencyLoader] private void load(GameHost gameHost) { @@ -110,6 +108,17 @@ namespace osu.Game.Tests.Visual.Menus exitViaBackButtonAndConfirm(); } + [Test] + public void TestOpenOptionsAndExitWithEscape() + { + AddStep("Enter menu", () => pressAndRelease(Key.Enter)); + AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition)); + AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left)); + AddAssert("Options overlay was opened", () => osuGame.Settings.State.Value == Visibility.Visible); + AddStep("Hide options overlay using escape", () => pressAndRelease(Key.Escape)); + AddAssert("Options overlay was closed", () => osuGame.Settings.State.Value == Visibility.Hidden); + } + private void pushAndConfirm(Func newScreen, string screenName) { Screen screen = null; @@ -117,7 +126,7 @@ namespace osu.Game.Tests.Visual.Menus { if (screenName == "song select") Logger.Log("fuck"); - + osuGame.ScreenStack.Push(screen = newScreen()); }); AddUntilStep($"Wait for new {screenName}", () => osuGame.ScreenStack.CurrentScreen == screen && screen.IsLoaded); @@ -148,6 +157,8 @@ namespace osu.Game.Tests.Visual.Menus public new BackButton BackButton => base.BackButton; + public new SettingsPanel Settings => base.Settings; + protected override Loader CreateLoader() => new TestLoader(); } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9fa1eb8aa7..e7c0d01f31 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -82,8 +82,11 @@ namespace osu.Game public readonly Bindable OverlayActivationMode = new Bindable(); protected OsuScreenStack ScreenStack; + protected BackButton BackButton; + protected SettingsPanel Settings; + private VolumeOverlay volume; private OsuLogo osuLogo; @@ -97,8 +100,6 @@ namespace osu.Game private readonly string[] args; - private SettingsPanel settings; - private readonly List overlays = new List(); private readonly List toolbarElements = new List(); @@ -483,7 +484,7 @@ namespace osu.Game loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); - loadComponentSingleFile(settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); + loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true); loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true); @@ -514,7 +515,7 @@ namespace osu.Game Add(externalLinkOpener = new ExternalLinkOpener()); - var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications }; + var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications }; overlays.AddRange(singleDisplaySideOverlays); foreach (var overlay in singleDisplaySideOverlays) @@ -567,7 +568,7 @@ namespace osu.Game { float offset = 0; - if (settings.State.Value == Visibility.Visible) + if (Settings.State.Value == Visibility.Visible) offset += ToolbarButton.WIDTH / 2; if (notifications.State.Value == Visibility.Visible) offset -= ToolbarButton.WIDTH / 2; @@ -575,7 +576,7 @@ namespace osu.Game screenContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint); } - settings.State.ValueChanged += _ => updateScreenOffset(); + Settings.State.ValueChanged += _ => updateScreenOffset(); notifications.State.ValueChanged += _ => updateScreenOffset(); } @@ -720,7 +721,7 @@ namespace osu.Game return true; case GlobalAction.ToggleSettings: - settings.ToggleVisibility(); + Settings.ToggleVisibility(); return true; case GlobalAction.ToggleDirect: From d05b9b1734bf9734ce9434721ef5ee990ef6dd38 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 1 Aug 2019 14:19:45 +0900 Subject: [PATCH 012/966] Use dummyAPI and move load check into MusicController --- .../Visual/Menus/TestSceneScreenNavigation.cs | 26 +++++++++++++------ osu.Game/OsuGame.cs | 2 +- osu.Game/Overlays/MusicController.cs | 4 +++ osu.Game/Screens/Multi/Multiplayer.cs | 2 +- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index f71e8dc2ce..88dac8d0ff 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -8,11 +8,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Screens; @@ -111,6 +111,7 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestOpenOptionsAndExitWithEscape() { + AddUntilStep("Wait for options to load", () => osuGame.Settings.IsLoaded); AddStep("Enter menu", () => pressAndRelease(Key.Enter)); AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition)); AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left)); @@ -122,13 +123,7 @@ namespace osu.Game.Tests.Visual.Menus private void pushAndConfirm(Func newScreen, string screenName) { Screen screen = null; - AddStep($"Push new {screenName}", () => - { - if (screenName == "song select") - Logger.Log("fuck"); - - osuGame.ScreenStack.Push(screen = newScreen()); - }); + AddStep($"Push new {screenName}", () => osuGame.ScreenStack.Push(screen = newScreen())); AddUntilStep($"Wait for new {screenName}", () => osuGame.ScreenStack.CurrentScreen == screen && screen.IsLoaded); } @@ -160,6 +155,21 @@ namespace osu.Game.Tests.Visual.Menus public new SettingsPanel Settings => base.Settings; protected override Loader CreateLoader() => new TestLoader(); + + private DependencyContainer dependencies; + + private DummyAPIAccess dummyAPI; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + protected override void LoadComplete() + { + base.LoadComplete(); + dependencies.CacheAs(dummyAPI = new DummyAPIAccess()); + + dummyAPI.Login("Rhythm Champion", "osu!"); + } } private class TestSongSelect : PlaySongSelect diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e7c0d01f31..63ec349d3d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -318,7 +318,7 @@ namespace osu.Game private void currentTrackCompleted() { - if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled && musicController.IsLoaded) + if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled) musicController.NextTrack(); } diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index abbcec5094..91ae92320a 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -316,6 +316,10 @@ namespace osu.Game.Overlays private void next(bool instant = false) { + // beatmapSets doesn't get populated until loading has completed. + if (!IsLoaded) + return; + if (!instant) queuedDirection = TransformDirection.Next; diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 3d9997e236..9550d883fd 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -168,7 +168,7 @@ namespace osu.Game.Screens.Multi public void APIStateChanged(IAPIProvider api, APIState state) { - if (RequireOnline && state != APIState.Online) + if (state != APIState.Online) forcefullyExit(); } From f0941a11b513b2f9a506d140124037f05d3235af Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 1 Aug 2019 21:22:08 +0900 Subject: [PATCH 013/966] Remove no longer needed property --- osu.Game/Screens/Multi/Multiplayer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 9550d883fd..90806bab6e 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -34,8 +34,6 @@ namespace osu.Game.Screens.Multi public override bool DisallowExternalBeatmapRulesetChanges => true; - protected virtual bool RequireOnline => true; - private readonly MultiplayerWaveContainer waves; private readonly OsuButton createButton; From 6ab9f645a2f436944d5a583b1faeefdf1e0d121a Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 1 Aug 2019 21:26:52 +0900 Subject: [PATCH 014/966] Remove usage of no longer needed property --- osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index 88dac8d0ff..08afe90de8 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -97,14 +97,14 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestExitMultiWithEscape() { - pushAndConfirm(() => new TestMultiplayer(), "multiplayer"); + pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - pushAndConfirm(() => new TestMultiplayer(), "multiplayer"); + pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); exitViaBackButtonAndConfirm(); } @@ -177,11 +177,6 @@ namespace osu.Game.Tests.Visual.Menus public ModSelectOverlay ModSelectOverlay => ModSelect; } - private class TestMultiplayer : Screens.Multi.Multiplayer - { - protected override bool RequireOnline => false; - } - private class TestLoader : Loader { protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(); From 1b5a9aecffdef0b307c3712d0d85992928b0d894 Mon Sep 17 00:00:00 2001 From: DTSDAO Date: Fri, 2 Aug 2019 23:34:25 +0800 Subject: [PATCH 015/966] Add iOS URL Scheme support --- .../Graphics/Containers/LinkFlowContainer.cs | 47 +--------------- osu.Game/Online/Chat/MessageFormatter.cs | 54 ++++++++++++++++++- osu.Game/OsuGame.cs | 22 ++++++++ osu.iOS/AppDelegate.cs | 7 ++- osu.iOS/Info.plist | 14 +++++ 5 files changed, 93 insertions(+), 51 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 15068d81c0..51a842fc84 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -86,52 +86,7 @@ namespace osu.Game.Graphics.Containers { RelativeSizeAxes = Axes.Both, TooltipText = tooltipText ?? (url != text ? url : string.Empty), - Action = action ?? (() => - { - switch (linkType) - { - case LinkAction.OpenBeatmap: - // TODO: proper query params handling - if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) - game?.ShowBeatmap(beatmapId); - break; - - case LinkAction.OpenBeatmapSet: - if (int.TryParse(linkArgument, out int setId)) - game?.ShowBeatmapSet(setId); - break; - - case LinkAction.OpenChannel: - try - { - channelManager?.OpenChannel(linkArgument); - } - catch (ChannelNotFoundException) - { - Logger.Log($"The requested channel \"{linkArgument}\" does not exist"); - } - - break; - - case LinkAction.OpenEditorTimestamp: - case LinkAction.JoinMultiplayerMatch: - case LinkAction.Spectate: - showNotImplementedError?.Invoke(); - break; - - case LinkAction.External: - game?.OpenUrlExternally(url); - break; - - case LinkAction.OpenUserProfile: - if (long.TryParse(linkArgument, out long userId)) - game?.ShowUser(userId); - break; - - default: - throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); - } - }), + Action = action ?? (() => LinkUtils.HandleLink(url, linkType, linkArgument, game, channelManager, showNotImplementedError)), }); return drawables; diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 4aaffdd161..ee8f45803b 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; +using osu.Framework.Logging; namespace osu.Game.Online.Chat { @@ -98,7 +100,7 @@ namespace osu.Game.Online.Chat } } - private static LinkDetails getLinkDetails(string url) + public static LinkDetails getLinkDetails(string url) { var args = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); args[0] = args[0].TrimEnd(':'); @@ -288,4 +290,54 @@ namespace osu.Game.Online.Chat public int CompareTo(Link otherLink) => Index > otherLink.Index ? 1 : -1; } + + public static class LinkUtils + { + public static void HandleLink(string url, LinkAction linkType, string linkArgument, OsuGame game, ChannelManager channelManager = null, Action showNotImplementedError = null) + { + switch (linkType) + { + case LinkAction.OpenBeatmap: + // TODO: proper query params handling + if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) + game?.ShowBeatmap(beatmapId); + break; + + case LinkAction.OpenBeatmapSet: + if (int.TryParse(linkArgument, out int setId)) + game?.ShowBeatmapSet(setId); + break; + + case LinkAction.OpenChannel: + try + { + channelManager?.OpenChannel(linkArgument); + } + catch (ChannelNotFoundException) + { + Logger.Log($"The requested channel \"{linkArgument}\" does not exist"); + } + + break; + + case LinkAction.OpenEditorTimestamp: + case LinkAction.JoinMultiplayerMatch: + case LinkAction.Spectate: + showNotImplementedError?.Invoke(); + break; + + case LinkAction.External: + game?.OpenUrlExternally(url); + break; + + case LinkAction.OpenUserProfile: + if (long.TryParse(linkArgument, out long userId)) + game?.ShowUser(userId); + break; + + default: + throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); + } + } + } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e71dd67bf2..5dea67253d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -43,6 +43,7 @@ using osu.Game.Scoring; using osu.Game.Screens.Select; using osu.Game.Utils; using LogLevel = osu.Framework.Logging.LogLevel; +using static osu.Game.Online.Chat.MessageFormatter; namespace osu.Game { @@ -90,6 +91,8 @@ namespace osu.Game private IntroScreen introScreen; + private bool loaded = false; + private Bindable configRuleset; private Bindable configSkin; @@ -190,10 +193,29 @@ namespace osu.Game Audio.AddAdjustment(AdjustableProperty.Volume, inactiveVolumeFade); Beatmap.BindValueChanged(beatmapChanged, true); + + loaded = true; } private ExternalLinkOpener externalLinkOpener; + public void HandleUrl(string url) + { + Logger.Log($"Request to handle url: {url}"); + if (loaded) + { + Action showNotImplementedError = () => notifications?.Post(new SimpleNotification + { + Text = @"This link type is not yet supported!", + Icon = FontAwesome.Solid.LifeRing, + }); + LinkDetails linkDetails = getLinkDetails(url); + Schedule(() => LinkUtils.HandleLink(url, linkDetails.Action, linkDetails.Argument, this, channelManager, showNotImplementedError)); + } + else + Scheduler.AddDelayed(() => HandleUrl(url), 1000); + } + public void OpenUrlExternally(string url) { if (url.StartsWith("/")) diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs index 9ef21e014c..e727305997 100644 --- a/osu.iOS/AppDelegate.cs +++ b/osu.iOS/AppDelegate.cs @@ -1,10 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Threading.Tasks; using Foundation; using osu.Framework.iOS; -using osu.Game; +using osu.Framework.Threading; using UIKit; namespace osu.iOS @@ -16,9 +15,9 @@ namespace osu.iOS protected override Framework.Game CreateGame() => game = new OsuGameIOS(); - public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation) + public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options) { - Task.Run(() => game.Import(url.Path)); + game.HandleUrl(url.AbsoluteString); return true; } } diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist index 4fbc67e27b..5fe8cd6d5b 100644 --- a/osu.iOS/Info.plist +++ b/osu.iOS/Info.plist @@ -107,5 +107,19 @@ + UIFileSharingEnabled + + CFBundleURLTypes + + + CFBundleURLSchemes + + osu + osump + + CFBundleTypeRole + Editor + + From 471103fd101180e78f2d54fc34d96cb5198dcada Mon Sep 17 00:00:00 2001 From: DTSDAO Date: Sat, 3 Aug 2019 00:00:22 +0800 Subject: [PATCH 016/966] Fix code format --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 1 - osu.Game/Online/Chat/MessageFormatter.cs | 2 +- osu.Game/OsuGame.cs | 8 +++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 51a842fc84..ab4629cfff 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Framework.Logging; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Users; diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index ee8f45803b..347139975e 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -100,7 +100,7 @@ namespace osu.Game.Online.Chat } } - public static LinkDetails getLinkDetails(string url) + public static LinkDetails GetLinkDetails(string url) { var args = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); args[0] = args[0].TrimEnd(':'); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5dea67253d..fa68142fea 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -91,7 +91,7 @@ namespace osu.Game private IntroScreen introScreen; - private bool loaded = false; + private bool loaded; private Bindable configRuleset; @@ -193,8 +193,6 @@ namespace osu.Game Audio.AddAdjustment(AdjustableProperty.Volume, inactiveVolumeFade); Beatmap.BindValueChanged(beatmapChanged, true); - - loaded = true; } private ExternalLinkOpener externalLinkOpener; @@ -202,6 +200,7 @@ namespace osu.Game public void HandleUrl(string url) { Logger.Log($"Request to handle url: {url}"); + if (loaded) { Action showNotImplementedError = () => notifications?.Post(new SimpleNotification @@ -402,6 +401,8 @@ namespace osu.Game protected override void LoadComplete() { + loaded = false; + base.LoadComplete(); // The next time this is updated is in UpdateAfterChildren, which occurs too late and results @@ -597,6 +598,7 @@ namespace osu.Game settings.State.ValueChanged += _ => updateScreenOffset(); notifications.State.ValueChanged += _ => updateScreenOffset(); + loaded = true; } public class GameIdleTracker : IdleTracker From c9e14c8f063afae562789111864fc094601a9202 Mon Sep 17 00:00:00 2001 From: DTSDAO Date: Sat, 3 Aug 2019 19:46:57 +0800 Subject: [PATCH 017/966] Fix typo --- osu.Game/Online/Chat/MessageFormatter.cs | 4 ++-- osu.Game/OsuGame.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 347139975e..73396ce4d2 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -78,7 +78,7 @@ namespace osu.Game.Online.Chat //since we just changed the line display text, offset any already processed links. result.Links.ForEach(l => l.Index -= l.Index > index ? m.Length - displayText.Length : 0); - var details = getLinkDetails(linkText); + var details = GetLinkDetails(linkText); result.Links.Add(new Link(linkText, index, displayText.Length, linkActionOverride ?? details.Action, details.Argument)); //adjust the offset for processing the current matches group. @@ -95,7 +95,7 @@ namespace osu.Game.Online.Chat var link = m.Groups["link"].Value; var indexLength = link.Length; - var details = getLinkDetails(link); + var details = GetLinkDetails(link); result.Links.Add(new Link(link, index, indexLength, details.Action, details.Argument)); } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index fa68142fea..c478ad0a57 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -208,7 +208,7 @@ namespace osu.Game Text = @"This link type is not yet supported!", Icon = FontAwesome.Solid.LifeRing, }); - LinkDetails linkDetails = getLinkDetails(url); + LinkDetails linkDetails = GetLinkDetails(url); Schedule(() => LinkUtils.HandleLink(url, linkDetails.Action, linkDetails.Argument, this, channelManager, showNotImplementedError)); } else From 0fe6585975a7efdf6b00a73f7be41593c7ea6e20 Mon Sep 17 00:00:00 2001 From: DTSDAO Date: Mon, 5 Aug 2019 22:30:35 +0800 Subject: [PATCH 018/966] Fix iOS importing --- osu.Game/Database/ArchiveModelManager.cs | 2 +- osu.Game/OsuGame.cs | 24 ++++++++---------------- osu.iOS/AppDelegate.cs | 6 +++++- osu.iOS/Info.plist | 2 ++ osu.iOS/OsuGameIOS.cs | 2 ++ 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index efb76deff8..37ea7b2ca9 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -54,7 +54,7 @@ namespace osu.Game.Database public virtual string[] HandledExtensions => new[] { ".zip" }; - public virtual bool SupportsImportFromStable => RuntimeInfo.IsDesktop; + public virtual bool SupportsImportFromStable => (RuntimeInfo.IsDesktop || RuntimeInfo.OS == RuntimeInfo.Platform.iOS); protected readonly FileStore Files; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b64f04de2a..846677a0a9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -91,8 +91,6 @@ namespace osu.Game private IntroScreen introScreen; - private bool loaded; - private Bindable configRuleset; private Bindable configSkin; @@ -201,18 +199,15 @@ namespace osu.Game { Logger.Log($"Request to handle url: {url}"); - if (loaded) + Action showNotImplementedError = () => notifications?.Post(new SimpleNotification { - Action showNotImplementedError = () => notifications?.Post(new SimpleNotification - { - Text = @"This link type is not yet supported!", - Icon = FontAwesome.Solid.LifeRing, - }); - LinkDetails linkDetails = GetLinkDetails(url); - Schedule(() => LinkUtils.HandleLink(url, linkDetails.Action, linkDetails.Argument, this, channelManager, showNotImplementedError)); - } - else - Scheduler.AddDelayed(() => HandleUrl(url), 1000); + Text = @"This link type is not yet supported!", + Icon = FontAwesome.Solid.LifeRing, + }); + + LinkDetails linkDetails = GetLinkDetails(url); + + Schedule(() => LinkUtils.HandleLink(url, linkDetails.Action, linkDetails.Argument, this, channelManager, showNotImplementedError)); } public void OpenUrlExternally(string url) @@ -403,8 +398,6 @@ namespace osu.Game protected override void LoadComplete() { - loaded = false; - base.LoadComplete(); // The next time this is updated is in UpdateAfterChildren, which occurs too late and results @@ -600,7 +593,6 @@ namespace osu.Game settings.State.ValueChanged += _ => updateScreenOffset(); notifications.State.ValueChanged += _ => updateScreenOffset(); - loaded = true; } public class GameIdleTracker : IdleTracker diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs index e727305997..07e0245195 100644 --- a/osu.iOS/AppDelegate.cs +++ b/osu.iOS/AppDelegate.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Threading.Tasks; using Foundation; using osu.Framework.iOS; using osu.Framework.Threading; @@ -17,7 +18,10 @@ namespace osu.iOS public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options) { - game.HandleUrl(url.AbsoluteString); + if (url.IsFileUrl) + Task.Run(() => game.Import(url.Path)); + else + Task.Run(() => game.HandleUrl(url.AbsoluteString)); return true; } } diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist index f3067bdcec..5fe8cd6d5b 100644 --- a/osu.iOS/Info.plist +++ b/osu.iOS/Info.plist @@ -14,6 +14,8 @@ 0.1.0 LSRequiresIPhoneOS + LSSupportsOpeningDocumentsInPlace + MinimumOSVersion 10.0 UIDeviceFamily diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs index 6cf18df9a6..ac66357fc9 100644 --- a/osu.iOS/OsuGameIOS.cs +++ b/osu.iOS/OsuGameIOS.cs @@ -3,12 +3,14 @@ using System; using Foundation; +using osu.Framework.Platform; using osu.Game; namespace osu.iOS { public class OsuGameIOS : OsuGame { + public override Storage GetStorageForStableInstall() => Storage; public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString()); } } From cf9a5baafae910e287196d8fe702b44e2c1f2b86 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 7 Aug 2019 14:51:24 +0900 Subject: [PATCH 019/966] Explicity dispose osuGame instances --- osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs | 3 +++ osu.Game/Overlays/MusicController.cs | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index 08afe90de8..663447d0b4 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -51,7 +51,10 @@ namespace osu.Game.Tests.Visual.Menus AddStep("Create new game instance", () => { if (osuGame != null) + { Remove(osuGame); + osuGame.Dispose(); + } osuGame = new TestOsuGame(); osuGame.SetHost(gameHost); diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 91ae92320a..abbcec5094 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -316,10 +316,6 @@ namespace osu.Game.Overlays private void next(bool instant = false) { - // beatmapSets doesn't get populated until loading has completed. - if (!IsLoaded) - return; - if (!instant) queuedDirection = TransformDirection.Next; From 411916d4a31b39725b58cbc549fd0a9001e691f5 Mon Sep 17 00:00:00 2001 From: DTSDAO Date: Wed, 7 Aug 2019 19:32:48 +0800 Subject: [PATCH 020/966] Move static method to Game class --- .../Graphics/Containers/LinkFlowContainer.cs | 2 +- osu.Game/Online/Chat/MessageFormatter.cs | 52 ------------------ osu.Game/OsuGame.cs | 55 +++++++++++++++++-- 3 files changed, 52 insertions(+), 57 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index ab4629cfff..ca9ffd06c6 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -85,7 +85,7 @@ namespace osu.Game.Graphics.Containers { RelativeSizeAxes = Axes.Both, TooltipText = tooltipText ?? (url != text ? url : string.Empty), - Action = action ?? (() => LinkUtils.HandleLink(url, linkType, linkArgument, game, channelManager, showNotImplementedError)), + Action = action ?? (() => game.HandleLink(url, linkType, linkArgument)), }); return drawables; diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 73396ce4d2..c875150091 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -3,9 +3,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text.RegularExpressions; -using osu.Framework.Logging; namespace osu.Game.Online.Chat { @@ -290,54 +288,4 @@ namespace osu.Game.Online.Chat public int CompareTo(Link otherLink) => Index > otherLink.Index ? 1 : -1; } - - public static class LinkUtils - { - public static void HandleLink(string url, LinkAction linkType, string linkArgument, OsuGame game, ChannelManager channelManager = null, Action showNotImplementedError = null) - { - switch (linkType) - { - case LinkAction.OpenBeatmap: - // TODO: proper query params handling - if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) - game?.ShowBeatmap(beatmapId); - break; - - case LinkAction.OpenBeatmapSet: - if (int.TryParse(linkArgument, out int setId)) - game?.ShowBeatmapSet(setId); - break; - - case LinkAction.OpenChannel: - try - { - channelManager?.OpenChannel(linkArgument); - } - catch (ChannelNotFoundException) - { - Logger.Log($"The requested channel \"{linkArgument}\" does not exist"); - } - - break; - - case LinkAction.OpenEditorTimestamp: - case LinkAction.JoinMultiplayerMatch: - case LinkAction.Spectate: - showNotImplementedError?.Invoke(); - break; - - case LinkAction.External: - game?.OpenUrlExternally(url); - break; - - case LinkAction.OpenUserProfile: - if (long.TryParse(linkArgument, out long userId)) - game?.ShowUser(userId); - break; - - default: - throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); - } - } - } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 846677a0a9..43f3f1f5b5 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -195,19 +195,66 @@ namespace osu.Game private ExternalLinkOpener externalLinkOpener; - public void HandleUrl(string url) + public void HandleLink(string url, LinkAction linkType, string linkArgument) { - Logger.Log($"Request to handle url: {url}"); - Action showNotImplementedError = () => notifications?.Post(new SimpleNotification { Text = @"This link type is not yet supported!", Icon = FontAwesome.Solid.LifeRing, }); + switch (linkType) + { + case LinkAction.OpenBeatmap: + // TODO: proper query params handling + if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) + ShowBeatmap(beatmapId); + break; + + case LinkAction.OpenBeatmapSet: + if (int.TryParse(linkArgument, out int setId)) + ShowBeatmapSet(setId); + break; + + case LinkAction.OpenChannel: + try + { + channelManager.OpenChannel(linkArgument); + } + catch (ChannelNotFoundException) + { + Logger.Log($"The requested channel \"{linkArgument}\" does not exist"); + } + + break; + + case LinkAction.OpenEditorTimestamp: + case LinkAction.JoinMultiplayerMatch: + case LinkAction.Spectate: + showNotImplementedError?.Invoke(); + break; + + case LinkAction.External: + OpenUrlExternally(url); + break; + + case LinkAction.OpenUserProfile: + if (long.TryParse(linkArgument, out long userId)) + ShowUser(userId); + break; + + default: + throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); + } + } + + public void HandleUrl(string url) + { + Logger.Log($"Request to handle url: {url}"); + LinkDetails linkDetails = GetLinkDetails(url); - Schedule(() => LinkUtils.HandleLink(url, linkDetails.Action, linkDetails.Argument, this, channelManager, showNotImplementedError)); + Schedule(() => HandleLink(url, linkDetails.Action, linkDetails.Argument)); } public void OpenUrlExternally(string url) From 37e430177384e047ce2ce932b280a22583c7d223 Mon Sep 17 00:00:00 2001 From: DTSDAO Date: Wed, 7 Aug 2019 20:16:22 +0800 Subject: [PATCH 021/966] Fix code format --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 11 +---------- osu.Game/OsuGame.cs | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index ca9ffd06c6..b03bc4e3aa 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -22,21 +22,12 @@ namespace osu.Game.Graphics.Containers } private OsuGame game; - private ChannelManager channelManager; - private Action showNotImplementedError; [BackgroundDependencyLoader(true)] - private void load(OsuGame game, NotificationOverlay notifications, ChannelManager channelManager) + private void load(OsuGame game) { // will be null in tests this.game = game; - this.channelManager = channelManager; - - showNotImplementedError = () => notifications?.Post(new SimpleNotification - { - Text = @"This link type is not yet supported!", - Icon = FontAwesome.Solid.LifeRing, - }); } public void AddLinks(string text, List links) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 43f3f1f5b5..82bf8abf94 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -231,7 +231,7 @@ namespace osu.Game case LinkAction.OpenEditorTimestamp: case LinkAction.JoinMultiplayerMatch: case LinkAction.Spectate: - showNotImplementedError?.Invoke(); + showNotImplementedError.Invoke(); break; case LinkAction.External: From 9f72e92e0e35dc4c71ba7d6d184334fbd5b732ca Mon Sep 17 00:00:00 2001 From: DTSDAO Date: Wed, 7 Aug 2019 20:27:39 +0800 Subject: [PATCH 022/966] Fix code format --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index b03bc4e3aa..66911d9615 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -8,8 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Game.Overlays; -using osu.Game.Overlays.Notifications; using osu.Game.Users; namespace osu.Game.Graphics.Containers From e3d52d8d7171076a28ddb67feaf130cf62a7ea3a Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 10 Aug 2019 12:22:45 +0200 Subject: [PATCH 023/966] Add NewsOverlay class --- osu.Game/Overlays/NewsOverlay.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 osu.Game/Overlays/NewsOverlay.cs diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs new file mode 100644 index 0000000000..76040a6086 --- /dev/null +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -0,0 +1,23 @@ +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; + +namespace osu.Game.Overlays +{ + public class NewsOverlay : FullscreenOverlay + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.PurpleLightAlternative + } + }; + } + } +} From 4b0ac381b7372a0ba2f6238e2890509c158debb2 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 10 Aug 2019 12:26:54 +0200 Subject: [PATCH 024/966] Add visual tests. --- .../Visual/Online/TestSceneNewsOverlay.cs | 17 +++++++++++++++++ osu.Game/Overlays/NewsOverlay.cs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs new file mode 100644 index 0000000000..3362d4700f --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs @@ -0,0 +1,17 @@ +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneNewsOverlay : OsuTestScene + { + private NewsOverlay news; + + protected override void LoadComplete() + { + base.LoadComplete(); + Add(news = new NewsOverlay()); + AddStep(@"Show", news.Show); + AddStep(@"Hide", news.Hide); + } + } +} diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 76040a6086..76b917b65d 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays new Box { RelativeSizeAxes = Axes.Both, - Colour = colours.PurpleLightAlternative + Colour = colours.PurpleDarkAlternative } }; } From b19c378fc8a7e5b571ed0e288b79c6e2ac628941 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 10 Aug 2019 12:53:34 +0200 Subject: [PATCH 025/966] Add NewsHeader class --- osu.Game/Overlays/News/NewsHeader.cs | 71 ++++++++++++++++++++++++++++ osu.Game/Overlays/NewsOverlay.cs | 21 +++++++- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/News/NewsHeader.cs diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs new file mode 100644 index 0000000000..43a514cdc6 --- /dev/null +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -0,0 +1,71 @@ +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.News +{ + public class NewsHeader : OverlayHeader + { + private const string front_page_string = "Front Page"; + + private NewsHeaderTitle title; + + public NewsHeader() + { + TabControl.AddItem(front_page_string); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + TabControl.AccentColour = colour.Violet; + } + + protected override Drawable CreateBackground() => new NewsHeaderBackground(); + + protected override Drawable CreateContent() => new Container(); + + protected override ScreenTitle CreateTitle() => title = new NewsHeaderTitle(); + + private class NewsHeaderBackground : Sprite + { + public NewsHeaderBackground() + { + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fill; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + Texture = textures.Get(@"Headers/changelog"); //using changelog bg until corresponding osu-resources pr is merged. + } + } + + private class NewsHeaderTitle : ScreenTitle + { + private const string article_string = "Article"; + + public bool IsReadingArticle + { + set => Section = value ? article_string : front_page_string; + } + + public NewsHeaderTitle() + { + Title = "News"; + IsReadingArticle = false; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AccentColour = colours.Violet; + } + } + } +} diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 76b917b65d..80088a25bc 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -1,12 +1,17 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Overlays.News; namespace osu.Game.Overlays { public class NewsOverlay : FullscreenOverlay { + private NewsHeader header; + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -16,7 +21,21 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, Colour = colours.PurpleDarkAlternative - } + }, + new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + header = new NewsHeader() + }, + }, + }, }; } } From 0e5561c783344856d751338f32e876cb373cb4a0 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 10 Aug 2019 16:12:42 +0200 Subject: [PATCH 026/966] Use News overlay resources --- osu.Game/Overlays/News/NewsHeader.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 43a514cdc6..fb02f7f105 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.News [BackgroundDependencyLoader] private void load(TextureStore textures) { - Texture = textures.Get(@"Headers/changelog"); //using changelog bg until corresponding osu-resources pr is merged. + Texture = textures.Get(@"Headers/news"); } } @@ -61,6 +61,8 @@ namespace osu.Game.Overlays.News IsReadingArticle = false; } + protected override Drawable CreateIcon() => new ScreenTitleIcon(@"Icons/news"); + [BackgroundDependencyLoader] private void load(OsuColour colours) { From b92e331730f2971c5fbe7b5afe0031e781c2c494 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 10 Aug 2019 17:06:52 +0200 Subject: [PATCH 027/966] Add tabcontrol logic to news overlay --- .../Visual/Online/TestSceneNewsOverlay.cs | 3 ++ osu.Game/Overlays/News/NewsHeader.cs | 35 ++++++++++++++++++- osu.Game/Overlays/NewsOverlay.cs | 13 +++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs index 3362d4700f..d5273801d8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs @@ -12,6 +12,9 @@ namespace osu.Game.Tests.Visual.Online Add(news = new NewsOverlay()); AddStep(@"Show", news.Show); AddStep(@"Hide", news.Hide); + + AddStep(@"Show front page", () => news.ShowFrontPage()); + AddStep(@"Custom article", () => news.Current.Value = "Test Article 101"); } } } diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index fb02f7f105..e887d48456 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -1,10 +1,12 @@ using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using System; namespace osu.Game.Overlays.News { @@ -14,9 +16,21 @@ namespace osu.Game.Overlays.News private NewsHeaderTitle title; + public readonly Bindable Current = new Bindable(null); + + public Action ShowFrontPage; + public NewsHeader() { TabControl.AddItem(front_page_string); + + TabControl.Current.ValueChanged += e => + { + if (e.NewValue == front_page_string) + ShowFrontPage?.Invoke(); + }; + + Current.ValueChanged += showArticle; } [BackgroundDependencyLoader] @@ -25,6 +39,25 @@ namespace osu.Game.Overlays.News TabControl.AccentColour = colour.Violet; } + private void showArticle(ValueChangedEvent e) + { + if (e.OldValue != null) + TabControl.RemoveItem(e.OldValue); + + if (e.NewValue != null) + { + TabControl.AddItem(e.NewValue); + TabControl.Current.Value = e.NewValue; + + title.IsReadingArticle = true; + } + else + { + TabControl.Current.Value = front_page_string; + title.IsReadingArticle = false; + } + } + protected override Drawable CreateBackground() => new NewsHeaderBackground(); protected override Drawable CreateContent() => new Container(); @@ -52,7 +85,7 @@ namespace osu.Game.Overlays.News public bool IsReadingArticle { - set => Section = value ? article_string : front_page_string; + set => Section = value ? article_string : front_page_string; } public NewsHeaderTitle() diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 80088a25bc..1506cbb288 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -1,4 +1,5 @@ using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -12,6 +13,8 @@ namespace osu.Game.Overlays { private NewsHeader header; + public readonly Bindable Current = new Bindable(null); + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -37,6 +40,16 @@ namespace osu.Game.Overlays }, }, }; + + header.Current.BindTo(Current); + header.ShowFrontPage = ShowFrontPage; + Current.TriggerChange(); + } + + public void ShowFrontPage() + { + Current.Value = null; + Show(); } } } From 87811afade5abfdbf6dc3a2503242f2be4be076b Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 12 Aug 2019 20:16:41 +0200 Subject: [PATCH 028/966] Add missing licence headers to added files. --- osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs | 5 ++++- osu.Game/Overlays/News/NewsHeader.cs | 5 ++++- osu.Game/Overlays/NewsOverlay.cs | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs index d5273801d8..546f6ac182 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs @@ -1,4 +1,7 @@ -using osu.Game.Overlays; +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index e887d48456..6a14828473 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// 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.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 1506cbb288..b509204c58 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// 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.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From aa6f8757eb955cc6179b928dc87038fcc3ff87cd Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 13 Aug 2019 12:26:06 +0900 Subject: [PATCH 029/966] remove string param, move menu check to method, add const padding --- .../Visual/Menus/TestSceneScreenNavigation.cs | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index 663447d0b4..efb4f3e83a 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -26,12 +26,14 @@ namespace osu.Game.Tests.Visual.Menus { public class TestSceneScreenNavigation : ManualInputManagerTestScene { + private const float click_padding = 25; + private GameHost gameHost; private TestOsuGame osuGame; - private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(25, osuGame.LayoutRectangle.Bottom - 25)); + private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(click_padding, osuGame.LayoutRectangle.Bottom - click_padding)); - private Vector2 optionsButtonPosition => osuGame.ToScreenSpace(new Vector2(25, 25)); + private Vector2 optionsButtonPosition => osuGame.ToScreenSpace(new Vector2(click_padding, click_padding)); [BackgroundDependencyLoader] private void load(GameHost gameHost) @@ -63,7 +65,7 @@ namespace osu.Game.Tests.Visual.Menus }); AddUntilStep("Wait for load", () => osuGame.IsLoaded); AddUntilStep("Wait for intro", () => osuGame.ScreenStack.CurrentScreen is IntroScreen); - AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded); + confirmAtMainMenu(); } [Test] @@ -71,7 +73,7 @@ namespace osu.Game.Tests.Visual.Menus { TestSongSelect songSelect = null; - pushAndConfirm(() => songSelect = new TestSongSelect(), "song select"); + pushAndConfirm(() => songSelect = new TestSongSelect()); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); AddStep("Press escape", () => pressAndRelease(Key.Escape)); @@ -84,7 +86,7 @@ namespace osu.Game.Tests.Visual.Menus { TestSongSelect songSelect = null; - pushAndConfirm(() => songSelect = new TestSongSelect(), "song select"); + pushAndConfirm(() => songSelect = new TestSongSelect()); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition)); @@ -100,14 +102,14 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestExitMultiWithEscape() { - pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); + pushAndConfirm(() => new Screens.Multi.Multiplayer()); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - pushAndConfirm(() => new Screens.Multi.Multiplayer(), "multiplayer"); + pushAndConfirm(() => new Screens.Multi.Multiplayer()); exitViaBackButtonAndConfirm(); } @@ -123,26 +125,28 @@ namespace osu.Game.Tests.Visual.Menus AddAssert("Options overlay was closed", () => osuGame.Settings.State.Value == Visibility.Hidden); } - private void pushAndConfirm(Func newScreen, string screenName) + private void pushAndConfirm(Func newScreen) { Screen screen = null; - AddStep($"Push new {screenName}", () => osuGame.ScreenStack.Push(screen = newScreen())); - AddUntilStep($"Wait for new {screenName}", () => osuGame.ScreenStack.CurrentScreen == screen && screen.IsLoaded); + AddStep("Push new screen", () => osuGame.ScreenStack.Push(screen = newScreen())); + AddUntilStep("Wait for new screen", () => osuGame.ScreenStack.CurrentScreen == screen && screen.IsLoaded); } private void exitViaEscapeAndConfirm() { AddStep("Press escape", () => pressAndRelease(Key.Escape)); - AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); + confirmAtMainMenu(); } private void exitViaBackButtonAndConfirm() { AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition)); AddStep("Click back button", () => InputManager.Click(MouseButton.Left)); - AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); + confirmAtMainMenu(); } + private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); + private void pressAndRelease(Key key) { InputManager.PressKey(key); From 480e489c44d28130edd5be8dca5d02763455cecb Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 14 Aug 2019 12:51:43 +0900 Subject: [PATCH 030/966] add back missing loaded check --- osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index efb4f3e83a..515f4cdce6 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Menus confirmAtMainMenu(); } - private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu); + private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded); private void pressAndRelease(Key key) { From 840d4741daf285b0c2541997f39b6fda309a492b Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 14 Aug 2019 20:24:36 +0200 Subject: [PATCH 031/966] Add NewsContent class and fix broken reference. --- osu.Game/Overlays/News/NewsContent.cs | 16 ++++++++++++++++ osu.Game/Overlays/News/NewsHeader.cs | 2 +- osu.Game/Overlays/NewsOverlay.cs | 10 +++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Overlays/News/NewsContent.cs diff --git a/osu.Game/Overlays/News/NewsContent.cs b/osu.Game/Overlays/News/NewsContent.cs new file mode 100644 index 0000000000..f0763285eb --- /dev/null +++ b/osu.Game/Overlays/News/NewsContent.cs @@ -0,0 +1,16 @@ +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Overlays.News +{ + public abstract class NewsContent : FillFlowContainer + { + public NewsContent() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Padding = new MarginPadding { Bottom = 100 }; + } + } +} diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index 6a14828473..27620ab523 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -97,7 +97,7 @@ namespace osu.Game.Overlays.News IsReadingArticle = false; } - protected override Drawable CreateIcon() => new ScreenTitleIcon(@"Icons/news"); + protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/news"); [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index b509204c58..b341321a46 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -15,6 +15,7 @@ namespace osu.Game.Overlays public class NewsOverlay : FullscreenOverlay { private NewsHeader header; + private Container content; public readonly Bindable Current = new Bindable(null); @@ -39,13 +40,20 @@ namespace osu.Game.Overlays Children = new Drawable[] { header = new NewsHeader() + { + ShowFrontPage = ShowFrontPage + }, + content = new Container() + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } }, }, }, }; header.Current.BindTo(Current); - header.ShowFrontPage = ShowFrontPage; Current.TriggerChange(); } From 46e71e9ead75227f63080ed4751e3f61228d1f40 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 14 Aug 2019 21:34:29 +0200 Subject: [PATCH 032/966] Add missing licence header --- osu.Game/Overlays/News/NewsContent.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/News/NewsContent.cs b/osu.Game/Overlays/News/NewsContent.cs index f0763285eb..26f92b3825 100644 --- a/osu.Game/Overlays/News/NewsContent.cs +++ b/osu.Game/Overlays/News/NewsContent.cs @@ -1,4 +1,7 @@ -using osu.Framework.Graphics; +// 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; using osu.Framework.Graphics.Containers; namespace osu.Game.Overlays.News From 4d1b1a4022d530d5c7fff5ceec3d04ffca641543 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 14 Aug 2019 21:52:36 +0200 Subject: [PATCH 033/966] Fix CI inspections --- osu.Game/Overlays/News/NewsContent.cs | 2 +- osu.Game/Overlays/NewsOverlay.cs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/News/NewsContent.cs b/osu.Game/Overlays/News/NewsContent.cs index 26f92b3825..16a8ed84b8 100644 --- a/osu.Game/Overlays/News/NewsContent.cs +++ b/osu.Game/Overlays/News/NewsContent.cs @@ -8,7 +8,7 @@ namespace osu.Game.Overlays.News { public abstract class NewsContent : FillFlowContainer { - public NewsContent() + protected NewsContent() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index b341321a46..aadca8883e 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -15,6 +15,8 @@ namespace osu.Game.Overlays public class NewsOverlay : FullscreenOverlay { private NewsHeader header; + + //ReSharper disable NotAccessedField.Local private Container content; public readonly Bindable Current = new Bindable(null); @@ -39,11 +41,11 @@ namespace osu.Game.Overlays Direction = FillDirection.Vertical, Children = new Drawable[] { - header = new NewsHeader() + header = new NewsHeader { ShowFrontPage = ShowFrontPage }, - content = new Container() + content = new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From a41356cf0efbae9a44e8c32a2544468d379ed7b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Aug 2019 16:30:46 +0900 Subject: [PATCH 034/966] Add android build automation via fastlane --- fastlane/Fastfile | 34 ++++++++++++++++++++++++++++++++++ fastlane/README.md | 19 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 0b60e28b0f..9cc5e4aa74 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -1,5 +1,39 @@ update_fastlane +platform :android do +desc 'Deploy to play store' + lane :beta do |options| + # update csproj version + update_version(options) + + build( + build_configuration: 'Release', + ) + + client = HTTPClient.new + changelog = client.get_content 'https://gist.githubusercontent.com/peppy/ab89c29dcc0dce95f39eb218e8fad197/raw' + changelog.gsub!('$BUILD_ID', options[:build]) + end + + desc 'Compile the project' + lane :build do + nuget_restore( + project_path: 'osu.Android.sln' + ) + + souyuz( + solution_path: 'osu.Android.sln', + platform: "android", + ) + end + + lane :update_version do |options| + options[:plist_path] = '../osu.iOS/Info.plist' + app_version(options) + end + +end + platform :ios do desc 'Deploy to testflight' lane :beta do |options| diff --git a/fastlane/README.md b/fastlane/README.md index fbccf1c8c0..6145620870 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -15,6 +15,25 @@ Install _fastlane_ using or alternatively using `brew cask install fastlane` # Available Actions +## Android +### android beta +``` +fastlane android beta +``` +Deploy to play store +### android build +``` +fastlane android build +``` +Compile the project +### android update_version +``` +fastlane android update_version +``` + + +---- + ## iOS ### ios beta ``` From af2ffac03a5fe99a4d62e0508e3e0f1e215d2be3 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 18 Aug 2019 14:52:26 +0200 Subject: [PATCH 035/966] Add global Top and Horizontal padding to NewsContent --- osu.Game/Overlays/News/NewsContent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/News/NewsContent.cs b/osu.Game/Overlays/News/NewsContent.cs index 16a8ed84b8..5ff210f9f5 100644 --- a/osu.Game/Overlays/News/NewsContent.cs +++ b/osu.Game/Overlays/News/NewsContent.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.News RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Direction = FillDirection.Vertical; - Padding = new MarginPadding { Bottom = 100 }; + Padding = new MarginPadding { Bottom = 100, Top = 20, Horizontal = 50 }; } } } From 43c51366637984cf8132fb81c38d21bc8a0ad28e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Aug 2019 17:22:20 +0900 Subject: [PATCH 036/966] Remove plist reference --- fastlane/Fastfile | 1 - 1 file changed, 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 9cc5e4aa74..f6eb95ca3d 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -28,7 +28,6 @@ desc 'Deploy to play store' end lane :update_version do |options| - options[:plist_path] = '../osu.iOS/Info.plist' app_version(options) end From 3d8b27abfaa698c7ff8e4ba2b07a3dbb48f7a798 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 8 Sep 2019 16:13:36 +0300 Subject: [PATCH 037/966] RotationAbsolute -> BidirectionalRotation --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 5 +++-- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs index 3ed3f3e981..5d7acb77bb 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Tests if (auto && !userTriggered && Time.Current > Spinner.StartTime + Spinner.Duration / 2 && Progress < 1) { // force completion only once to not break human interaction - Disc.RotationAbsolute = Spinner.SpinsRequired * 360; + Disc.BidirectionalRotation = Spinner.SpinsRequired * 360; auto = false; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 49aaa2aaea..c7bcf2526a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -1,6 +1,7 @@ // 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 osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -136,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables positionBindable.BindTo(HitObject.PositionBindable); } - public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1); + public float Progress => MathHelper.Clamp(Disc.BidirectionalRotation / 360 / Spinner.SpinsRequired, 0, 1); protected override void CheckForResult(bool userTriggered, double timeOffset) { @@ -188,7 +189,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables circle.Rotation = Disc.Rotation; Ticks.Rotation = Disc.Rotation; - spmCounter.SetRotation(Disc.RotationAbsolute); + spmCounter.SetRotation(Disc.BidirectionalRotation); float relativeCircleScale = Spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight; Disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, Easing.OutQuint); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 448a2eada7..b9d5674b34 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -82,11 +82,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private float lastAngle; private float currentRotation; - public float RotationAbsolute; + public float BidirectionalRotation; private int completeTick; - private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360)); + private bool updateCompleteTick() => completeTick != (completeTick = (int)(BidirectionalRotation / 360)); private bool rotationTransferred; protected override void Update() @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces lastAngle -= 360; currentRotation += thisAngle - lastAngle; - RotationAbsolute += Math.Abs(thisAngle - lastAngle); + BidirectionalRotation += Math.Abs(thisAngle - lastAngle) * Math.Sign(Time.Current - lastTime); } lastAngle = thisAngle; From f5f2713a17c62037786bb0010b2fd3cd480cd97c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 8 Sep 2019 16:14:14 +0300 Subject: [PATCH 038/966] Account angle change negatively on rewind --- osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index b9d5674b34..5b2b3bcd42 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -85,8 +85,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public float BidirectionalRotation; private int completeTick; + private double lastTime; private bool updateCompleteTick() => completeTick != (completeTick = (int)(BidirectionalRotation / 360)); + private bool rotationTransferred; protected override void Update() @@ -112,6 +114,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces currentRotation += thisAngle - lastAngle; BidirectionalRotation += Math.Abs(thisAngle - lastAngle) * Math.Sign(Time.Current - lastTime); + lastTime = Time.Current; } lastAngle = thisAngle; From 9defcb0e9945785dc4edf44a444a6015f78517f6 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 8 Sep 2019 21:37:50 +0300 Subject: [PATCH 039/966] Remove redundant using directive --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index c7bcf2526a..a8dc275fb5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.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 System; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From 55cc3de57e3346419b3eaf05403a0d2e7ea01e3b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Sep 2019 11:59:58 +0900 Subject: [PATCH 040/966] Always specify a configuration --- fastlane/Fastfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index f6eb95ca3d..dd35fa0b46 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -6,9 +6,7 @@ desc 'Deploy to play store' # update csproj version update_version(options) - build( - build_configuration: 'Release', - ) + build() client = HTTPClient.new changelog = client.get_content 'https://gist.githubusercontent.com/peppy/ab89c29dcc0dce95f39eb218e8fad197/raw' @@ -22,6 +20,7 @@ desc 'Deploy to play store' ) souyuz( + build_configuration: 'Release', solution_path: 'osu.Android.sln', platform: "android", ) From c4aee11fe08c60db192388be63cad4287cb70f65 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 9 Sep 2019 15:35:18 +0300 Subject: [PATCH 041/966] Revert renaming changes --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 4 ++-- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs index 5d7acb77bb..3ed3f3e981 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Tests if (auto && !userTriggered && Time.Current > Spinner.StartTime + Spinner.Duration / 2 && Progress < 1) { // force completion only once to not break human interaction - Disc.BidirectionalRotation = Spinner.SpinsRequired * 360; + Disc.RotationAbsolute = Spinner.SpinsRequired * 360; auto = false; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index a8dc275fb5..49aaa2aaea 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables positionBindable.BindTo(HitObject.PositionBindable); } - public float Progress => MathHelper.Clamp(Disc.BidirectionalRotation / 360 / Spinner.SpinsRequired, 0, 1); + public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1); protected override void CheckForResult(bool userTriggered, double timeOffset) { @@ -188,7 +188,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables circle.Rotation = Disc.Rotation; Ticks.Rotation = Disc.Rotation; - spmCounter.SetRotation(Disc.BidirectionalRotation); + spmCounter.SetRotation(Disc.RotationAbsolute); float relativeCircleScale = Spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight; Disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, Easing.OutQuint); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 5b2b3bcd42..2ae420a5e2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -82,12 +82,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private float lastAngle; private float currentRotation; - public float BidirectionalRotation; + public float RotationAbsolute; private int completeTick; private double lastTime; - private bool updateCompleteTick() => completeTick != (completeTick = (int)(BidirectionalRotation / 360)); + private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360)); private bool rotationTransferred; @@ -113,8 +113,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces lastAngle -= 360; currentRotation += thisAngle - lastAngle; - BidirectionalRotation += Math.Abs(thisAngle - lastAngle) * Math.Sign(Time.Current - lastTime); lastTime = Time.Current; + RotationAbsolute += Math.Abs(thisAngle - lastAngle) * Math.Sign(Clock.ElapsedFrameTime); } lastAngle = thisAngle; From aec04dcf904cc1a8ba2f80b6298f82ef3e419b57 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 9 Sep 2019 15:36:20 +0300 Subject: [PATCH 042/966] Use Clock.ElapsedFrameTime instead --- osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 2ae420a5e2..c45e98cc76 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -85,8 +85,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public float RotationAbsolute; private int completeTick; - private double lastTime; - private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360)); private bool rotationTransferred; @@ -113,7 +111,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces lastAngle -= 360; currentRotation += thisAngle - lastAngle; - lastTime = Time.Current; RotationAbsolute += Math.Abs(thisAngle - lastAngle) * Math.Sign(Clock.ElapsedFrameTime); } From 7b1ff38df7652b3eee6c159f50125f7809cefb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 9 Sep 2019 23:41:51 +0200 Subject: [PATCH 043/966] Implement line-buffered reader Add a line-buffered reader decorator operating on StreamReader instances. The decorator has two main operations - PeekLine(), which allows to see the next line in the stream without consuming it, ReadLine(), which consumes and returns the next line in the stream, and ReadToEnd() which reads all the remaining text in the stream (including the unconsumed peeked line). Peeking line-per-line uses an internal queue of lines that have been read ahead from the underlying stream. The addition of the line-buffered reader is a workaround solution to a problem with decoding. At current selecting a decoder works by irreversibly reading the first line from the stream and looking for a magic string that indicates the type of decoder to use. It might however be possible for a file to be valid in format, just missing a header. In such a case a lack of a line-buffered reader makes it impossible to reparse the content of that first line. Introducing it will however allow to peek the first line for magic first. - If magic is found in the first line, GetDecoder() will peek it and use it to return the correct Decoder instance. Note that in the case of JsonBeatmapDecoder the magic is the opening JSON object brace, and therefore must not be consumed. - If magic is not found, the fallback decoder will be able to consume it using ReadLine() in Decode(). This commit additionally contains basic unit tests for the reader. Suggested-by: Aergwyn --- .../Beatmaps/IO/LineBufferedReaderTest.cs | 133 ++++++++++++++++++ osu.Game/IO/LineBufferedReader.cs | 70 +++++++++ 2 files changed, 203 insertions(+) create mode 100644 osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs create mode 100644 osu.Game/IO/LineBufferedReader.cs diff --git a/osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs new file mode 100644 index 0000000000..b582ca0a6f --- /dev/null +++ b/osu.Game.Tests/Beatmaps/IO/LineBufferedReaderTest.cs @@ -0,0 +1,133 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using System.Text; +using NUnit.Framework; +using osu.Game.IO; + +namespace osu.Game.Tests.Beatmaps.IO +{ + [TestFixture] + public class LineBufferedReaderTest + { + [Test] + public void TestReadLineByLine() + { + const string contents = @"line 1 +line 2 +line 3"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) + using (var bufferedReader = new LineBufferedReader(stream)) + { + Assert.AreEqual("line 1", bufferedReader.ReadLine()); + Assert.AreEqual("line 2", bufferedReader.ReadLine()); + Assert.AreEqual("line 3", bufferedReader.ReadLine()); + Assert.IsNull(bufferedReader.ReadLine()); + } + } + + [Test] + public void TestPeekLineOnce() + { + const string contents = @"line 1 +peek this +line 3"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) + using (var bufferedReader = new LineBufferedReader(stream)) + { + Assert.AreEqual("line 1", bufferedReader.ReadLine()); + Assert.AreEqual("peek this", bufferedReader.PeekLine()); + Assert.AreEqual("peek this", bufferedReader.ReadLine()); + Assert.AreEqual("line 3", bufferedReader.ReadLine()); + Assert.IsNull(bufferedReader.ReadLine()); + } + } + + [Test] + public void TestPeekLineMultipleTimes() + { + const string contents = @"peek this once +line 2 +peek this a lot"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) + using (var bufferedReader = new LineBufferedReader(stream)) + { + Assert.AreEqual("peek this once", bufferedReader.PeekLine()); + Assert.AreEqual("peek this once", bufferedReader.ReadLine()); + Assert.AreEqual("line 2", bufferedReader.ReadLine()); + Assert.AreEqual("peek this a lot", bufferedReader.PeekLine()); + Assert.AreEqual("peek this a lot", bufferedReader.PeekLine()); + Assert.AreEqual("peek this a lot", bufferedReader.PeekLine()); + Assert.AreEqual("peek this a lot", bufferedReader.ReadLine()); + Assert.IsNull(bufferedReader.ReadLine()); + } + } + + [Test] + public void TestPeekLineAtEndOfStream() + { + const string contents = @"first line +second line"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) + using (var bufferedReader = new LineBufferedReader(stream)) + { + Assert.AreEqual("first line", bufferedReader.ReadLine()); + Assert.AreEqual("second line", bufferedReader.ReadLine()); + Assert.IsNull(bufferedReader.PeekLine()); + Assert.IsNull(bufferedReader.ReadLine()); + Assert.IsNull(bufferedReader.PeekLine()); + } + } + + [Test] + public void TestPeekReadLineOnEmptyStream() + { + using (var stream = new MemoryStream()) + using (var bufferedReader = new LineBufferedReader(stream)) + { + Assert.IsNull(bufferedReader.PeekLine()); + Assert.IsNull(bufferedReader.ReadLine()); + Assert.IsNull(bufferedReader.ReadLine()); + Assert.IsNull(bufferedReader.PeekLine()); + } + } + + [Test] + public void TestReadToEndNoPeeks() + { + const string contents = @"first line +second line"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) + using (var bufferedReader = new LineBufferedReader(stream)) + { + Assert.AreEqual(contents, bufferedReader.ReadToEnd()); + } + } + + [Test] + public void TestReadToEndAfterReadsAndPeeks() + { + const string contents = @"this line is gone +this one shouldn't be +these ones +definitely not"; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents))) + using (var bufferedReader = new LineBufferedReader(stream)) + { + Assert.AreEqual("this line is gone", bufferedReader.ReadLine()); + Assert.AreEqual("this one shouldn't be", bufferedReader.PeekLine()); + const string ending = @"this one shouldn't be +these ones +definitely not"; + Assert.AreEqual(ending, bufferedReader.ReadToEnd()); + } + } + } +} diff --git a/osu.Game/IO/LineBufferedReader.cs b/osu.Game/IO/LineBufferedReader.cs new file mode 100644 index 0000000000..66dee1181f --- /dev/null +++ b/osu.Game/IO/LineBufferedReader.cs @@ -0,0 +1,70 @@ +// 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.Collections.Generic; +using System.IO; +using System.Text; + +namespace osu.Game.IO +{ + /// + /// A -like decorator (with more limited API) for s + /// that allows lines to be peeked without consuming. + /// + public class LineBufferedReader : IDisposable + { + private readonly StreamReader streamReader; + private readonly Queue lineBuffer; + + public LineBufferedReader(Stream stream) + { + streamReader = new StreamReader(stream); + lineBuffer = new Queue(); + } + + /// + /// Reads the next line from the stream without consuming it. + /// + public string PeekLine() + { + if (lineBuffer.Count > 0) + return lineBuffer.Peek(); + + var line = streamReader.ReadLine(); + if (line != null) + lineBuffer.Enqueue(line); + return line; + } + + /// + /// Reads the next line from the stream and consumes it. + /// + public string ReadLine() => lineBuffer.Count > 0 ? lineBuffer.Dequeue() : streamReader.ReadLine(); + + /// + /// Reads the stream to its end and returns the text read. + /// This includes any peeked but unconsumed lines. + /// + public string ReadToEnd() + { + var remainingText = streamReader.ReadToEnd(); + if (lineBuffer.Count == 0) + return remainingText; + + var builder = new StringBuilder(); + + // this might not be completely correct due to varying platform line endings + while (lineBuffer.Count > 0) + builder.AppendLine(lineBuffer.Dequeue()); + builder.Append(remainingText); + + return builder.ToString(); + } + + public void Dispose() + { + streamReader?.Dispose(); + } + } +} From 11eda44d3451c889469af4e8e30d522b04d2dd15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Sep 2019 00:43:30 +0200 Subject: [PATCH 044/966] Migrate decoding to line-buffered reader Migrate all usages of StreamReader in the context of decoding beatmaps, storyboards or skins to the new LineBufferedReader. --- osu.Game.Rulesets.Osu.Tests/StackingTest.cs | 3 +- .../Formats/LegacyBeatmapDecoderTest.cs | 42 +++++++++---------- .../Beatmaps/Formats/LegacyDecoderTest.cs | 4 +- .../Formats/LegacyStoryboardDecoderTest.cs | 6 +-- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 5 ++- .../Beatmaps/IO/OszArchiveReaderTest.cs | 3 +- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 6 +-- osu.Game.Tests/WaveformTestBeatmap.cs | 3 +- osu.Game/Beatmaps/BeatmapManager.cs | 5 ++- .../Beatmaps/BeatmapManager_WorkingBeatmap.cs | 8 ++-- osu.Game/Beatmaps/Formats/Decoder.cs | 9 ++-- .../Beatmaps/Formats/JsonBeatmapDecoder.cs | 7 +--- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 3 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 4 +- .../Formats/LegacyStoryboardDecoder.cs | 3 +- osu.Game/Skinning/LegacySkin.cs | 3 +- .../Tests/Beatmaps/BeatmapConversionTest.cs | 3 +- .../Beatmaps/DifficultyCalculatorTest.cs | 3 +- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 3 +- 19 files changed, 64 insertions(+), 59 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs index e8b99e86f9..871afdb09d 100644 --- a/osu.Game.Rulesets.Osu.Tests/StackingTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/StackingTest.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using NUnit.Framework; using osu.Game.Beatmaps; +using osu.Game.IO; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Tests.Beatmaps; @@ -21,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Tests public void TestStacking() { using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(beatmap_data))) - using (var reader = new StreamReader(stream)) + using (var reader = new LineBufferedReader(stream)) { var beatmap = Decoder.GetDecoder(reader).Decode(reader); var converted = new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty()); diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 535320530d..6a77c6ca96 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.IO; using NUnit.Framework; using osuTK; using osuTK.Graphics; @@ -13,6 +12,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; +using osu.Game.IO; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; @@ -30,13 +30,9 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeBeatmapVersion() { using (var resStream = TestResources.OpenResource("beatmap-version.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var decoder = Decoder.GetDecoder(stream); - - stream.BaseStream.Position = 0; - stream.DiscardBufferedData(); - var working = new TestWorkingBeatmap(decoder.Decode(stream)); Assert.AreEqual(6, working.BeatmapInfo.BeatmapVersion); @@ -51,7 +47,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var beatmap = decoder.Decode(stream); var beatmapInfo = beatmap.BeatmapInfo; @@ -75,7 +71,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder(); using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var beatmapInfo = decoder.Decode(stream).BeatmapInfo; @@ -101,7 +97,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder(); using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var beatmap = decoder.Decode(stream); var beatmapInfo = beatmap.BeatmapInfo; @@ -126,7 +122,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder(); using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty; @@ -145,7 +141,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var beatmap = decoder.Decode(stream); var metadata = beatmap.Metadata; @@ -164,7 +160,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var beatmap = decoder.Decode(stream); var controlPoints = beatmap.ControlPointInfo; @@ -239,7 +235,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("overlapping-control-points.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var controlPoints = decoder.Decode(stream).ControlPointInfo; @@ -271,7 +267,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacySkinDecoder(); using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var comboColors = decoder.Decode(stream).ComboColours; @@ -297,7 +293,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder(); using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -320,7 +316,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder(); using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var beatmap = decoder.Decode(stream); @@ -343,7 +339,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -371,7 +367,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("controlpoint-custom-samplebank.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -393,7 +389,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("hitobject-custom-samplebank.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -411,7 +407,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("hitobject-file-samples.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -431,7 +427,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("slider-samples.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -475,7 +471,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var resStream = TestResources.OpenResource("hitobject-no-addition-bank.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var hitObjects = decoder.Decode(stream).HitObjects; @@ -489,7 +485,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; using (var badResStream = TestResources.OpenResource("invalid-events.osu")) - using (var badStream = new StreamReader(badResStream)) + using (var badStream = new LineBufferedReader(badResStream)) { Assert.DoesNotThrow(() => decoder.Decode(badStream)); } diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs index b4d219456c..335a6aeeb0 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs @@ -2,9 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.IO; using NUnit.Framework; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Beatmaps.Formats @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LineLoggingDecoder(14); using (var resStream = TestResources.OpenResource("comments.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { decoder.Decode(stream); diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index 953763c95d..66d53d7e7b 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.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.IO; using System.Linq; using NUnit.Framework; using osuTK; using osu.Framework.Graphics; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.Storyboards; using osu.Game.Tests.Resources; @@ -21,7 +21,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyStoryboardDecoder(); using (var resStream = TestResources.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var storyboard = decoder.Decode(stream); @@ -94,7 +94,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new LegacyStoryboardDecoder(); using (var resStream = TestResources.OpenResource("variable-with-suffix.osb")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var storyboard = decoder.Decode(stream); diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 4859abbb8e..63346b8c9d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.IO.Serialization; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; @@ -148,13 +149,13 @@ namespace osu.Game.Tests.Beatmaps.Formats private Beatmap decode(string filename, out Beatmap jsonDecoded) { using (var stream = TestResources.OpenResource(filename)) - using (var sr = new StreamReader(stream)) + using (var sr = new LineBufferedReader(stream)) { var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr); using (var ms = new MemoryStream()) using (var sw = new StreamWriter(ms)) - using (var sr2 = new StreamReader(ms)) + using (var sr2 = new LineBufferedReader(ms)) { sw.Write(legacyDecoded.Serialize()); sw.Flush(); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 37e0565df0..022b2c1a59 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Tests.Resources; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.IO.Archives; namespace osu.Game.Tests.Beatmaps.IO @@ -50,7 +51,7 @@ namespace osu.Game.Tests.Beatmaps.IO Beatmap beatmap; - using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) + using (var stream = new LineBufferedReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) beatmap = Decoder.GetDecoder(stream).Decode(stream); var meta = beatmap.Metadata; diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 8bd846518b..0d96dd08da 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -2,8 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.IO; using NUnit.Framework; +using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Tests.Resources; using osuTK.Graphics; @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Skins var decoder = new LegacySkinDecoder(); using (var resStream = TestResources.OpenResource(hasColours ? "skin.ini" : "skin-empty.ini")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var comboColors = decoder.Decode(stream).ComboColours; @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Skins var decoder = new LegacySkinDecoder(); using (var resStream = TestResources.OpenResource("skin.ini")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var config = decoder.Decode(stream); diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs index db9576b5fa..0d16a78f75 100644 --- a/osu.Game.Tests/WaveformTestBeatmap.cs +++ b/osu.Game.Tests/WaveformTestBeatmap.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Video; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.Tests.Resources; @@ -56,7 +57,7 @@ namespace osu.Game.Tests private Beatmap createTestBeatmap() { using (var beatmapStream = getBeatmapStream()) - using (var beatmapReader = new StreamReader(beatmapStream)) + using (var beatmapReader = new LineBufferedReader(beatmapStream)) return Decoder.GetDecoder(beatmapReader).Decode(beatmapReader); } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index b9ed3664ef..372eec50fd 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -20,6 +20,7 @@ using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Beatmaps.Formats; using osu.Game.Database; +using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -264,7 +265,7 @@ namespace osu.Game.Beatmaps } Beatmap beatmap; - using (var stream = new StreamReader(reader.GetStream(mapName))) + using (var stream = new LineBufferedReader(reader.GetStream(mapName))) beatmap = Decoder.GetDecoder(stream).Decode(stream); return new BeatmapSetInfo @@ -287,7 +288,7 @@ namespace osu.Game.Beatmaps { using (var raw = reader.GetStream(name)) using (var ms = new MemoryStream()) //we need a memory stream so we can seek - using (var sr = new StreamReader(ms)) + using (var sr = new LineBufferedReader(ms)) { raw.CopyTo(ms); ms.Position = 0; diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index 1d00c94ef2..b879b92f01 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.IO; using System.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Track; @@ -11,6 +10,7 @@ using osu.Framework.Graphics.Video; using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Storyboards; @@ -33,7 +33,7 @@ namespace osu.Game.Beatmaps { try { - using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) return Decoder.GetDecoder(stream).Decode(stream); } catch @@ -127,7 +127,7 @@ namespace osu.Game.Beatmaps try { - using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) { var decoder = Decoder.GetDecoder(stream); @@ -136,7 +136,7 @@ namespace osu.Game.Beatmaps storyboard = decoder.Decode(stream); else { - using (var secondaryStream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) + using (var secondaryStream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) storyboard = decoder.Decode(stream, secondaryStream); } } diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index 953e50eadc..0f1b617809 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using osu.Game.IO; namespace osu.Game.Beatmaps.Formats { @@ -13,15 +14,15 @@ namespace osu.Game.Beatmaps.Formats { protected virtual TOutput CreateTemplateObject() => new TOutput(); - public TOutput Decode(StreamReader primaryStream, params StreamReader[] otherStreams) + public TOutput Decode(LineBufferedReader primaryStream, params LineBufferedReader[] otherStreams) { var output = CreateTemplateObject(); - foreach (StreamReader stream in otherStreams.Prepend(primaryStream)) + foreach (LineBufferedReader stream in otherStreams.Prepend(primaryStream)) ParseStreamInto(stream, output); return output; } - protected abstract void ParseStreamInto(StreamReader stream, TOutput output); + protected abstract void ParseStreamInto(LineBufferedReader stream, TOutput output); } public abstract class Decoder @@ -39,7 +40,7 @@ namespace osu.Game.Beatmaps.Formats /// Retrieves a to parse a . /// /// A stream pointing to the . - public static Decoder GetDecoder(StreamReader stream) + public static Decoder GetDecoder(LineBufferedReader stream) where T : new() { if (stream == null) diff --git a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs index d8482b200f..988968fa42 100644 --- a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.IO; +using osu.Game.IO; using osu.Game.IO.Serialization; namespace osu.Game.Beatmaps.Formats @@ -13,11 +13,8 @@ namespace osu.Game.Beatmaps.Formats AddDecoder("{", m => new JsonBeatmapDecoder()); } - protected override void ParseStreamInto(StreamReader stream, Beatmap output) + protected override void ParseStreamInto(LineBufferedReader stream, Beatmap output) { - stream.BaseStream.Position = 0; - stream.DiscardBufferedData(); - stream.ReadToEnd().DeserializeInto(output); foreach (var hitObject in output.HitObjects) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 0532790f0a..6e34fd8e90 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -8,6 +8,7 @@ using osu.Framework.IO.File; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.IO; namespace osu.Game.Beatmaps.Formats { @@ -41,7 +42,7 @@ namespace osu.Game.Beatmaps.Formats offset = FormatVersion < 5 ? 24 : 0; } - protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap) + protected override void ParseStreamInto(LineBufferedReader stream, Beatmap beatmap) { this.beatmap = beatmap; this.beatmap.BeatmapInfo.BeatmapVersion = FormatVersion; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 9a8197ad82..83d20da458 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -3,10 +3,10 @@ using System; using System.Collections.Generic; -using System.IO; using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.IO; using osuTK.Graphics; namespace osu.Game.Beatmaps.Formats @@ -21,7 +21,7 @@ namespace osu.Game.Beatmaps.Formats FormatVersion = version; } - protected override void ParseStreamInto(StreamReader stream, T output) + protected override void ParseStreamInto(LineBufferedReader stream, T output) { Section section = Section.None; diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 14c6ea5c8e..a8f8dbf69d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -10,6 +10,7 @@ using osuTK; using osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.IO.File; +using osu.Game.IO; using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats @@ -35,7 +36,7 @@ namespace osu.Game.Beatmaps.Formats AddDecoder(@"[Events]", m => new LegacyStoryboardDecoder()); } - protected override void ParseStreamInto(StreamReader stream, Storyboard storyboard) + protected override void ParseStreamInto(LineBufferedReader stream, Storyboard storyboard) { this.storyboard = storyboard; base.ParseStreamInto(stream, storyboard); diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 0b1076be01..fea15458e4 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Audio; +using osu.Game.IO; using osu.Game.Rulesets.Scoring; using osuTK.Graphics; @@ -35,7 +36,7 @@ namespace osu.Game.Skinning { Stream stream = storage?.GetStream(filename); if (stream != null) - using (StreamReader reader = new StreamReader(stream)) + using (LineBufferedReader reader = new LineBufferedReader(stream)) Configuration = new LegacySkinDecoder().Decode(reader); else Configuration = new DefaultSkinConfiguration(); diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 3fc9662b17..e99b5fc5fb 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Video; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; @@ -142,7 +143,7 @@ namespace osu.Game.Tests.Beatmaps private IBeatmap getBeatmap(string name) { using (var resStream = openResource($"{resource_namespace}.{name}.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var decoder = Decoder.GetDecoder(stream); ((LegacyBeatmapDecoder)decoder).ApplyOffsets = false; diff --git a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs index 108fa8ff71..748a52d1c5 100644 --- a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs +++ b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs @@ -7,6 +7,7 @@ using System.Reflection; using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; +using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -26,7 +27,7 @@ namespace osu.Game.Tests.Beatmaps private WorkingBeatmap getBeatmap(string name) { using (var resStream = openResource($"{resource_namespace}.{name}.osu")) - using (var stream = new StreamReader(resStream)) + using (var stream = new LineBufferedReader(resStream)) { var decoder = Decoder.GetDecoder(stream); ((LegacyBeatmapDecoder)decoder).ApplyOffsets = false; diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index b77a8508ad..d6f92ba086 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using osu.Game.Beatmaps; +using osu.Game.IO; using osu.Game.Rulesets; using Decoder = osu.Game.Beatmaps.Formats.Decoder; @@ -39,7 +40,7 @@ namespace osu.Game.Tests.Beatmaps private static Beatmap createTestBeatmap() { using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) - using (var reader = new StreamReader(stream)) + using (var reader = new LineBufferedReader(stream)) return Decoder.GetDecoder(reader).Decode(reader); } From 86588778b170b363b2e7156a9ffa08ba32e15f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Sep 2019 22:06:10 +0200 Subject: [PATCH 045/966] Implement fallback decoder registration After the preparatory introduction of LineBufferedReader, it is now possible to introduce registration of fallback decoders that won't drop input supplied in the first line of the file. A fallback decoder is used when the magic in the first line of the file does not match any of the other known decoders. In such a case, the fallback decoder is constructed and provided a LineBufferedReader instance. The process of matching magic only peeks the first non-empty line, so it is available for re-reading in Decode() using ReadLine(). There can be only one fallback decoder per type; a second attempt of registering a fallback will result in an exception to avoid bugs. To address the issue of parsing failing on badly or non-headered files, set the legacy decoders for Beatmaps and Storyboards as the fallbacks. Due to non-trivial logic, several new, passing unit tests with possible edge cases also included. --- .../Formats/LegacyBeatmapDecoderTest.cs | 101 ++++++++++++++++++ .../Beatmaps/IO/ImportBeatmapTest.cs | 2 +- osu.Game.Tests/Resources/corrupted-header.osu | 5 + .../empty-line-instead-of-header.osu | 5 + .../Resources/empty-lines-at-start.osu | 8 ++ osu.Game.Tests/Resources/missing-header.osu | 4 + .../Resources/no-empty-line-after-header.osu | 4 + osu.Game.Tests/osu.Game.Tests.csproj | 7 ++ osu.Game/Beatmaps/Formats/Decoder.cs | 41 +++++-- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 1 + .../Formats/LegacyStoryboardDecoder.cs | 1 + osu.Game/IO/LineBufferedReader.cs | 2 + 12 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 osu.Game.Tests/Resources/corrupted-header.osu create mode 100644 osu.Game.Tests/Resources/empty-line-instead-of-header.osu create mode 100644 osu.Game.Tests/Resources/empty-lines-at-start.osu create mode 100644 osu.Game.Tests/Resources/missing-header.osu create mode 100644 osu.Game.Tests/Resources/no-empty-line-after-header.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 6a77c6ca96..f6c0dbbecf 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.IO; using NUnit.Framework; using osuTK; using osuTK.Graphics; @@ -490,5 +491,105 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.DoesNotThrow(() => decoder.Decode(badStream)); } } + + [Test] + public void TestFallbackDecoderForCorruptedHeader() + { + Decoder decoder = null; + Beatmap beatmap = null; + + using (var resStream = TestResources.OpenResource("corrupted-header.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); + Assert.IsInstanceOf(decoder); + Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); + Assert.IsNotNull(beatmap); + Assert.AreEqual("Beatmap with corrupted header", beatmap.Metadata.Title); + Assert.AreEqual("Evil Hacker", beatmap.Metadata.AuthorString); + } + } + + [Test] + public void TestFallbackDecoderForMissingHeader() + { + Decoder decoder = null; + Beatmap beatmap = null; + + using (var resStream = TestResources.OpenResource("missing-header.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); + Assert.IsInstanceOf(decoder); + Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); + Assert.IsNotNull(beatmap); + Assert.AreEqual("Beatmap with no header", beatmap.Metadata.Title); + Assert.AreEqual("Incredibly Evil Hacker", beatmap.Metadata.AuthorString); + } + } + + [Test] + public void TestDecodeFileWithEmptyLinesAtStart() + { + Decoder decoder = null; + Beatmap beatmap = null; + + using (var resStream = TestResources.OpenResource("empty-lines-at-start.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); + Assert.IsInstanceOf(decoder); + Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); + Assert.IsNotNull(beatmap); + Assert.AreEqual("Empty lines at start", beatmap.Metadata.Title); + Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.AuthorString); + } + } + + [Test] + public void TestDecodeFileWithEmptyLinesAndNoHeader() + { + Decoder decoder = null; + Beatmap beatmap = null; + + using (var resStream = TestResources.OpenResource("empty-line-instead-of-header.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); + Assert.IsInstanceOf(decoder); + Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); + Assert.IsNotNull(beatmap); + Assert.AreEqual("The dog ate the file header", beatmap.Metadata.Title); + Assert.AreEqual("Why does this keep happening", beatmap.Metadata.AuthorString); + } + } + + [Test] + public void TestDecodeFileWithContentImmediatelyAfterHeader() + { + Decoder decoder = null; + Beatmap beatmap = null; + + using (var resStream = TestResources.OpenResource("no-empty-line-after-header.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); + Assert.IsInstanceOf(decoder); + Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); + Assert.IsNotNull(beatmap); + Assert.AreEqual("No empty line delimiting header from contents", beatmap.Metadata.Title); + Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.AuthorString); + } + } + + [Test] + public void TestDecodeEmptyFile() + { + using (var resStream = new MemoryStream()) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.Throws(() => Decoder.GetDecoder(stream)); + } + } } } diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index ad0ed00989..0686073292 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Beatmaps.IO var breakTemp = TestResources.GetTestBeatmapForImport(); - MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 }); + MemoryStream brokenOsu = new MemoryStream(); MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp)); File.Delete(breakTemp); diff --git a/osu.Game.Tests/Resources/corrupted-header.osu b/osu.Game.Tests/Resources/corrupted-header.osu new file mode 100644 index 0000000000..92701a4a7d --- /dev/null +++ b/osu.Game.Tests/Resources/corrupted-header.osu @@ -0,0 +1,5 @@ +ow computerosu file format v14 + +[Metadata] +Title: Beatmap with corrupted header +Creator: Evil Hacker diff --git a/osu.Game.Tests/Resources/empty-line-instead-of-header.osu b/osu.Game.Tests/Resources/empty-line-instead-of-header.osu new file mode 100644 index 0000000000..91ecf8d84a --- /dev/null +++ b/osu.Game.Tests/Resources/empty-line-instead-of-header.osu @@ -0,0 +1,5 @@ + + +[Metadata] +Title: The dog ate the file header +Creator: Why does this keep happening \ No newline at end of file diff --git a/osu.Game.Tests/Resources/empty-lines-at-start.osu b/osu.Game.Tests/Resources/empty-lines-at-start.osu new file mode 100644 index 0000000000..cb3b1761a2 --- /dev/null +++ b/osu.Game.Tests/Resources/empty-lines-at-start.osu @@ -0,0 +1,8 @@ + + + +osu file format v14 + +[Metadata] +Title: Empty lines at start +Creator: Edge Case Hunter \ No newline at end of file diff --git a/osu.Game.Tests/Resources/missing-header.osu b/osu.Game.Tests/Resources/missing-header.osu new file mode 100644 index 0000000000..95fac0d79b --- /dev/null +++ b/osu.Game.Tests/Resources/missing-header.osu @@ -0,0 +1,4 @@ +[Metadata] + +Title: Beatmap with no header +Creator: Incredibly Evil Hacker diff --git a/osu.Game.Tests/Resources/no-empty-line-after-header.osu b/osu.Game.Tests/Resources/no-empty-line-after-header.osu new file mode 100644 index 0000000000..9db2b7c01c --- /dev/null +++ b/osu.Game.Tests/Resources/no-empty-line-after-header.osu @@ -0,0 +1,4 @@ +osu file format v14 +[Metadata] +Title: No empty line delimiting header from contents +Creator: Edge Case Hunter \ No newline at end of file diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 84f67c9319..9dc3e85e1b 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,5 +1,12 @@  + + + + + + + diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index 0f1b617809..4a539cc33f 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -28,6 +28,7 @@ namespace osu.Game.Beatmaps.Formats public abstract class Decoder { private static readonly Dictionary>> decoders = new Dictionary>>(); + private static readonly Dictionary> fallback_decoders = new Dictionary>(); static Decoder() { @@ -49,21 +50,31 @@ namespace osu.Game.Beatmaps.Formats if (!decoders.TryGetValue(typeof(T), out var typedDecoders)) throw new IOException(@"Unknown decoder type"); - string line; + // start off with the first line of the file + string line = stream.PeekLine()?.Trim(); - do + while (line != null && line.Length == 0) { - line = stream.ReadLine()?.Trim(); - } while (line != null && line.Length == 0); + // consume the previously peeked empty line and advance to the next one + stream.ReadLine(); + line = stream.PeekLine()?.Trim(); + } if (line == null) - throw new IOException(@"Unknown file format (null)"); + throw new IOException("Unknown file format (null)"); var decoder = typedDecoders.Select(d => line.StartsWith(d.Key, StringComparison.InvariantCulture) ? d.Value : null).FirstOrDefault(); - if (decoder == null) - throw new IOException($@"Unknown file format ({line})"); - return (Decoder)decoder.Invoke(line); + // it's important the magic does NOT get consumed here, since sometimes it's part of the structure + // (see JsonBeatmapDecoder - the magic string is the opening brace) + // decoder implementations should therefore not die on receiving their own magic + if (decoder != null) + return (Decoder)decoder.Invoke(line); + + if (!fallback_decoders.TryGetValue(typeof(T), out var fallbackDecoder)) + throw new IOException($"Unknown file format ({line})"); + + return (Decoder)fallbackDecoder.Invoke(); } /// @@ -78,5 +89,19 @@ namespace osu.Game.Beatmaps.Formats typedDecoders[magic] = constructor; } + + /// + /// Registers a fallback decoder instantiation function. + /// The fallback will be returned if the first line of the decoded stream does not match any known magic. + /// + /// Type of object being decoded. + /// A function that constructs the fallback. + protected static void SetFallbackDecoder(Func constructor) + { + if (fallback_decoders.ContainsKey(typeof(T))) + throw new InvalidOperationException($"A fallback decoder was already added for type {typeof(T)}."); + + fallback_decoders[typeof(T)] = constructor; + } } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 6e34fd8e90..786b7611b5 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -26,6 +26,7 @@ namespace osu.Game.Beatmaps.Formats public static void Register() { AddDecoder(@"osu file format v", m => new LegacyBeatmapDecoder(Parsing.ParseInt(m.Split('v').Last()))); + SetFallbackDecoder(() => new LegacyBeatmapDecoder()); } /// diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index a8f8dbf69d..5dbd67d304 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -34,6 +34,7 @@ namespace osu.Game.Beatmaps.Formats // note that this isn't completely correct AddDecoder(@"osu file format v", m => new LegacyStoryboardDecoder()); AddDecoder(@"[Events]", m => new LegacyStoryboardDecoder()); + SetFallbackDecoder(() => new LegacyStoryboardDecoder()); } protected override void ParseStreamInto(LineBufferedReader stream, Storyboard storyboard) diff --git a/osu.Game/IO/LineBufferedReader.cs b/osu.Game/IO/LineBufferedReader.cs index 66dee1181f..aab761afd8 100644 --- a/osu.Game/IO/LineBufferedReader.cs +++ b/osu.Game/IO/LineBufferedReader.cs @@ -25,6 +25,7 @@ namespace osu.Game.IO /// /// Reads the next line from the stream without consuming it. + /// Subsequent calls to without a will return the same string. /// public string PeekLine() { @@ -39,6 +40,7 @@ namespace osu.Game.IO /// /// Reads the next line from the stream and consumes it. + /// If a line was peeked, that same line will then be consumed and returned. /// public string ReadLine() => lineBuffer.Count > 0 ? lineBuffer.Dequeue() : streamReader.ReadLine(); From 29fcab65f9a2e553dd9c9cd550173612f1b74303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Sep 2019 22:40:52 +0200 Subject: [PATCH 046/966] Remove superfluous csproj entries --- osu.Game.Tests/osu.Game.Tests.csproj | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 9dc3e85e1b..84f67c9319 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,12 +1,5 @@  - - - - - - - From dd9f620c2364e35c1f1185f2f4b5a43893b5874f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Sep 2019 22:45:34 +0200 Subject: [PATCH 047/966] Fix misleading xmldoc --- osu.Game/Beatmaps/Formats/Decoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index 4a539cc33f..045eb2d14d 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -92,7 +92,7 @@ namespace osu.Game.Beatmaps.Formats /// /// Registers a fallback decoder instantiation function. - /// The fallback will be returned if the first line of the decoded stream does not match any known magic. + /// The fallback will be returned if the first non-empty line of the decoded stream does not match any known magic. /// /// Type of object being decoded. /// A function that constructs the fallback. From 78931c8e23f304e0b39387b6d8d355ff64c01555 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 15:59:46 +0200 Subject: [PATCH 048/966] Implement notification when user has track or master volume muted This took around under a hour to implement, it has the same behavior and content from osu!stable. A notification will show up when the user has either its master or track volume set to the minimum, clicking it will set it to the default values. --- osu.Game/Screens/Play/PlayerLoader.cs | 46 ++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 5396321160..b8d5fc7bda 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -19,6 +20,8 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Input; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Menu; using osu.Game.Screens.Play.HUD; @@ -54,6 +57,8 @@ namespace osu.Game.Screens.Play private InputManager inputManager; + private NotificationOverlay notificationOverlay; + private IdleTracker idleTracker; public PlayerLoader(Func createPlayer) @@ -68,7 +73,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audioManager, NotificationOverlay notificationOverlay) { InternalChild = (content = new LogoTrackingContainer { @@ -101,6 +106,10 @@ namespace osu.Game.Screens.Play }); loadNewPlayer(); + + this.notificationOverlay = notificationOverlay; + + checkVolume(audioManager); } private void playerLoaded(Player player) => info.Loading = false; @@ -145,6 +154,12 @@ namespace osu.Game.Screens.Play content.FadeOut(250); } + private void checkVolume(AudioManager audio) + { + if (audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue) + notificationOverlay.Post(new MutedNotification()); + } + public override void OnEntering(IScreen last) { base.OnEntering(last); @@ -473,5 +488,34 @@ namespace osu.Game.Screens.Play Loading = true; } } + + private class MutedNotification : SimpleNotification + { + public MutedNotification() + { + this.Text = "Your music volume is set to 0%! Click here to restore it."; + } + + public override bool IsImportant => true; + + public override bool RequestsFocus => true; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay) + { + Icon = FontAwesome.Solid.VolumeMute; + IconBackgound.Colour = colours.RedDark; + + Activated = delegate + { + notificationOverlay.Hide(); + + audioManager.Volume.SetDefault(); + audioManager.VolumeTrack.SetDefault(); + + return true; + }; + } + } } } From 4a10e6c44e767012cc93266b5c0a9041e6a8cf82 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 16:11:45 +0200 Subject: [PATCH 049/966] Use ResolvedAttribute for NotificationOverlay --- osu.Game/Screens/Play/PlayerLoader.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index b8d5fc7bda..aaf750b9f7 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -57,7 +57,8 @@ namespace osu.Game.Screens.Play private InputManager inputManager; - private NotificationOverlay notificationOverlay; + [Resolved] + private NotificationOverlay notificationOverlay { get; set; } private IdleTracker idleTracker; @@ -107,8 +108,6 @@ namespace osu.Game.Screens.Play loadNewPlayer(); - this.notificationOverlay = notificationOverlay; - checkVolume(audioManager); } From 72af640df7316e646fe0c80ffcf2b9fa7b73f2d3 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 16:31:40 +0200 Subject: [PATCH 050/966] Expose VolumeOverlay as available dependencies --- osu.Game/OsuGame.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 8fa8ffaf9b..b07cd84bc3 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -485,7 +485,8 @@ namespace osu.Game toolbarElements.Add(d); }); - loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add); + dependencies.Cache(loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add)); + loadComponentSingleFile(new OnScreenDisplay(), Add, true); loadComponentSingleFile(musicController = new MusicController(), Add, true); From 0afb5c5bb05f4a9b9e54f43b6d97f4b166a10b3d Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 16:31:57 +0200 Subject: [PATCH 051/966] Expose muted state from VolumeOverlay --- osu.Game/Overlays/VolumeOverlay.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index e6204a3179..ff3cbcd575 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -32,6 +32,12 @@ namespace osu.Game.Overlays private readonly BindableDouble muteAdjustment = new BindableDouble(); + public bool IsMuted + { + get => muteButton.Current.Value; + set => muteButton.Current.Value = value; + } + [BackgroundDependencyLoader] private void load(AudioManager audio, OsuColour colours) { From 00e46fdefed6be79e6542464342a0e8a345c32e0 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 16:32:23 +0200 Subject: [PATCH 052/966] Add check if game is muted by MuteButton --- osu.Game/Screens/Play/PlayerLoader.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index aaf750b9f7..a00f005827 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -57,10 +58,13 @@ namespace osu.Game.Screens.Play private InputManager inputManager; + private IdleTracker idleTracker; + [Resolved] private NotificationOverlay notificationOverlay { get; set; } - private IdleTracker idleTracker; + [Resolved] + private VolumeOverlay volumeOverlay { get; set; } public PlayerLoader(Func createPlayer) { @@ -155,7 +159,7 @@ namespace osu.Game.Screens.Play private void checkVolume(AudioManager audio) { - if (audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue) + if (volumeOverlay.IsMuted || audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue) notificationOverlay.Post(new MutedNotification()); } @@ -500,7 +504,7 @@ namespace osu.Game.Screens.Play public override bool RequestsFocus => true; [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay) + private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay) { Icon = FontAwesome.Solid.VolumeMute; IconBackgound.Colour = colours.RedDark; @@ -509,6 +513,7 @@ namespace osu.Game.Screens.Play { notificationOverlay.Hide(); + volumeOverlay.IsMuted = false; audioManager.Volume.SetDefault(); audioManager.VolumeTrack.SetDefault(); From 811a08d18ff2736b52382b95ba48b80544ff27f0 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 16:50:01 +0200 Subject: [PATCH 053/966] Use Bindable instead of bool --- osu.Game/Overlays/VolumeOverlay.cs | 6 +----- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index ff3cbcd575..0c08e0eb6e 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -32,11 +32,7 @@ namespace osu.Game.Overlays private readonly BindableDouble muteAdjustment = new BindableDouble(); - public bool IsMuted - { - get => muteButton.Current.Value; - set => muteButton.Current.Value = value; - } + public Bindable IsMuted => muteButton.Current; [BackgroundDependencyLoader] private void load(AudioManager audio, OsuColour colours) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index a00f005827..baeec27412 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -159,7 +159,7 @@ namespace osu.Game.Screens.Play private void checkVolume(AudioManager audio) { - if (volumeOverlay.IsMuted || audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue) + if (volumeOverlay.IsMuted.Value || audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue) notificationOverlay.Post(new MutedNotification()); } @@ -513,7 +513,7 @@ namespace osu.Game.Screens.Play { notificationOverlay.Hide(); - volumeOverlay.IsMuted = false; + volumeOverlay.IsMuted.Value = false; audioManager.Volume.SetDefault(); audioManager.VolumeTrack.SetDefault(); From 08ab4e508f07b774f83c35063cb7d5216aecb421 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 17:15:52 +0200 Subject: [PATCH 054/966] Use loadComponentSingleFile for caching --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b07cd84bc3..d539fe0f50 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -485,7 +485,7 @@ namespace osu.Game toolbarElements.Add(d); }); - dependencies.Cache(loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add)); + loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add, true); loadComponentSingleFile(new OnScreenDisplay(), Add, true); From ec788ac09d8ac8343e374187725fbb8a7c4cef24 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 17:20:07 +0200 Subject: [PATCH 055/966] Make notification only show up once per session --- osu.Game/Screens/Play/PlayerLoader.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index baeec27412..3bce6fa1ed 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -66,6 +66,8 @@ namespace osu.Game.Screens.Play [Resolved] private VolumeOverlay volumeOverlay { get; set; } + private bool muteWarningShownOnce = false; + public PlayerLoader(Func createPlayer) { this.createPlayer = createPlayer; @@ -159,8 +161,12 @@ namespace osu.Game.Screens.Play private void checkVolume(AudioManager audio) { - if (volumeOverlay.IsMuted.Value || audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue) + //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. + if (!muteWarningShownOnce && (volumeOverlay.IsMuted.Value || audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue)) + { notificationOverlay.Post(new MutedNotification()); + muteWarningShownOnce = true; + } } public override void OnEntering(IScreen last) From e3884658af0be36a364e8637b70fea1f2b20ff08 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 17:36:53 +0200 Subject: [PATCH 056/966] Resolve code inspection errors --- osu.Game/Screens/Play/PlayerLoader.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 3bce6fa1ed..d78f36f6de 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -66,7 +65,7 @@ namespace osu.Game.Screens.Play [Resolved] private VolumeOverlay volumeOverlay { get; set; } - private bool muteWarningShownOnce = false; + private bool muteWarningShownOnce; public PlayerLoader(Func createPlayer) { @@ -500,10 +499,7 @@ namespace osu.Game.Screens.Play private class MutedNotification : SimpleNotification { - public MutedNotification() - { - this.Text = "Your music volume is set to 0%! Click here to restore it."; - } + public MutedNotification() => Text = "Your music volume is set to 0%! Click here to restore it."; public override bool IsImportant => true; From ecce12981e7bea177c784912d6adc360805be57e Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 15 Sep 2019 17:47:44 +0200 Subject: [PATCH 057/966] Use block body for constructor to fix remaining code inspection issue --- osu.Game/Screens/Play/PlayerLoader.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index d78f36f6de..df55b738e1 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -499,7 +499,10 @@ namespace osu.Game.Screens.Play private class MutedNotification : SimpleNotification { - public MutedNotification() => Text = "Your music volume is set to 0%! Click here to restore it."; + public MutedNotification() + { + Text = "Your music volume is set to 0%! Click here to restore it."; + } public override bool IsImportant => true; From 220fdd0a044105e268cccfe9c113c1dce6fcf668 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Sep 2019 06:56:52 +0200 Subject: [PATCH 058/966] Make muteWarningShownOnce static ... so it will actually get an instance per osu session. --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index df55b738e1..dbb6c47943 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.Play [Resolved] private VolumeOverlay volumeOverlay { get; set; } - private bool muteWarningShownOnce; + private static bool muteWarningShownOnce; public PlayerLoader(Func createPlayer) { From 78b6062100d83db9f6bc5c35f99a62c4038527d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Sep 2019 17:54:12 +0900 Subject: [PATCH 059/966] Update fastlane version --- Gemfile.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f7c19064b4..ac46fddb41 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,9 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.0) - addressable (2.6.0) - public_suffix (>= 2.0.2, < 4.0) + CFPropertyList (3.0.1) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) atomos (0.1.3) babosa (1.0.2) claide (1.0.3) @@ -26,8 +26,8 @@ GEM http-cookie (~> 1.0.0) faraday_middleware (0.13.1) faraday (>= 0.7.4, < 1.0) - fastimage (2.1.5) - fastlane (2.129.0) + fastimage (2.1.7) + fastlane (2.131.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) babosa (>= 1.0.2, < 2.0.0) @@ -77,9 +77,9 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.0) signet (~> 0.9) - google-cloud-core (1.3.0) + google-cloud-core (1.3.1) google-cloud-env (~> 1.0) - google-cloud-env (1.2.0) + google-cloud-env (1.2.1) faraday (~> 0.11) google-cloud-storage (1.16.0) digest-crc (~> 0.4) @@ -100,9 +100,9 @@ GEM json (2.2.0) jwt (2.1.0) memoist (0.16.0) - mime-types (3.2.2) + mime-types (3.3) mime-types-data (~> 3.2015) - mime-types-data (3.2019.0331) + mime-types-data (3.2019.0904) mini_magick (4.9.5) mini_portile2 (2.4.0) multi_json (1.13.1) @@ -121,14 +121,14 @@ GEM uber (< 0.2.0) retriable (3.1.2) rouge (2.0.7) - rubyzip (1.2.3) + rubyzip (1.2.4) security (0.1.3) signet (0.11.0) addressable (~> 2.3) faraday (~> 0.9) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.5) + simctl (1.6.6) CFPropertyList naturally slack-notifier (2.3.2) From 7bc4b4f98164bfa0d052c51b4540cb76afe10dc9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Sep 2019 18:08:11 +0900 Subject: [PATCH 060/966] Explicitly specify solution in beta lane --- fastlane/Fastfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index dd35fa0b46..e4a6bc4585 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -3,6 +3,9 @@ update_fastlane platform :android do desc 'Deploy to play store' lane :beta do |options| + + options[:solution_path] = 'osu.Android.sln' + # update csproj version update_version(options) From 9543c277845bfeb1d1eaa282700c863a50ec0c21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Sep 2019 19:10:41 +0900 Subject: [PATCH 061/966] Add full upload support --- fastlane/Fastfile | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index e4a6bc4585..906d284bc9 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -4,16 +4,21 @@ platform :android do desc 'Deploy to play store' lane :beta do |options| - options[:solution_path] = 'osu.Android.sln' - # update csproj version - update_version(options) + update_version( + solution_path: 'osu.Android.sln', + version: options[:version], + build: options[:build], + ) build() - client = HTTPClient.new - changelog = client.get_content 'https://gist.githubusercontent.com/peppy/ab89c29dcc0dce95f39eb218e8fad197/raw' - changelog.gsub!('$BUILD_ID', options[:build]) + supply( + apk: './osu.Android/bin/Release/sh.ppy.osulazer-Signed.apk', + package_name: 'sh.ppy.osulazer', + track: 'alpha', # upload to alpha, we can promote it later + json_key: options[:json_key], + ) end desc 'Compile the project' From c3221e1a3623d3c0cc5134aef738fbed3acbd24a Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 18 Sep 2019 23:27:26 +0200 Subject: [PATCH 062/966] Prepare classes for player loader test scene --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 90 +++++++++++++++++-- osu.Game/Screens/Play/PlayerLoader.cs | 16 +++- 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index ab519360ac..dc099b14b9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -3,14 +3,20 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; using osu.Framework.Screens; +using osu.Game.Graphics.Containers; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; @@ -24,19 +30,35 @@ namespace osu.Game.Tests.Visual.Gameplay public class TestScenePlayerLoader : ManualInputManagerTestScene { private TestPlayerLoader loader; - private OsuScreenStack stack; + private TestPlayerLoaderContainer container; + private TestPlayer player; + + [Resolved] + private AudioManager audioManager { get; set; } [SetUp] public void Setup() => Schedule(() => { - InputManager.Child = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; + ResetPlayer(false); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); }); + /// + /// Sets the input manager child to a new test player loader container instance. + /// + /// If the test player should behave like the production one. + public void ResetPlayer(bool interactive) + { + player = new TestPlayer(interactive, interactive); + loader = new TestPlayerLoader(() => player); + container = new TestPlayerLoaderContainer(loader); + InputManager.Child = container; + } + [Test] public void TestBlockLoadViaMouseMovement() { - AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false)))); + AddStep("load dummy beatmap", () => ResetPlayer(false)); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20); AddAssert("loader still active", () => loader.IsCurrentScreen()); @@ -49,13 +71,13 @@ namespace osu.Game.Tests.Visual.Gameplay Player player = null; SlowLoadPlayer slowPlayer = null; - AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer(false, false)))); + AddStep("load dummy beatmap", () => ResetPlayer(false)); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); AddUntilStep("wait for player to be current", () => player.IsCurrentScreen()); AddStep("load slow dummy beatmap", () => { - stack.Push(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + InputManager.Children = container = new TestPlayerLoaderContainer(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000); }); @@ -65,7 +87,6 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestModReinstantiation() { - TestPlayer player = null; TestMod gameMod = null; TestMod playerMod1 = null; TestMod playerMod2 = null; @@ -73,7 +94,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("load player", () => { Mods.Value = new[] { gameMod = new TestMod() }; - stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer())); + ResetPlayer(true); }); AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen()); @@ -97,6 +118,61 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("player mods applied", () => playerMod2.Applied); } + [Test] + public void TestMutedNotification() + { + AddStep("set master volume to 0%", () => audioManager.Volume.Value = 0); + AddStep("reset notification lock", () => PlayerLoader.ResetNotificationLock()); + //AddStep("reset notification overlay", () => notificationOverlay); + AddStep("load player", () => ResetPlayer(false)); + AddUntilStep("wait for player", () => player.IsLoaded); + + AddAssert("check for notification", () => container.NotificationOverlay.UnreadCount.Value == 1); + AddAssert("click notification", () => + { + var scrollContainer = container.NotificationOverlay.Children.Last() as OsuScrollContainer; + var flowContainer = scrollContainer.Children.First() as FillFlowContainer; + return flowContainer.Children.First().First().Click(); + }); + AddAssert("check master volume", () => audioManager.Volume.IsDefault); + + AddStep("restart player", () => + { + var lastPlayer = player; + player = null; + lastPlayer.Restart(); + }); + } + + private class TestPlayerLoaderContainer : Container + { + private TestPlayerLoader loader; + + [Cached] + public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }; + + [Cached] + public VolumeOverlay VolumeOverlay { get; } = new VolumeOverlay + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + }; + + public TestPlayerLoaderContainer(TestPlayerLoader testPlayerLoader) + { + Children = new Drawable[] + { + loader = testPlayerLoader, + NotificationOverlay, + VolumeOverlay + }; + } + } + private class TestPlayerLoader : PlayerLoader { public new VisualSettings VisualSettings => base.VisualSettings; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index dbb6c47943..8f2435d2f7 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -65,6 +65,9 @@ namespace osu.Game.Screens.Play [Resolved] private VolumeOverlay volumeOverlay { get; set; } + [Resolved] + private AudioManager audioManager { get; set; } + private static bool muteWarningShownOnce; public PlayerLoader(Func createPlayer) @@ -79,7 +82,7 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader] - private void load(AudioManager audioManager, NotificationOverlay notificationOverlay) + private void load() { InternalChild = (content = new LogoTrackingContainer { @@ -112,8 +115,6 @@ namespace osu.Game.Screens.Play }); loadNewPlayer(); - - checkVolume(audioManager); } private void playerLoaded(Player player) => info.Loading = false; @@ -212,6 +213,7 @@ namespace osu.Game.Screens.Play { inputManager = GetContainingInputManager(); base.LoadComplete(); + checkVolume(audioManager); } private ScheduledDelegate pushDebounce; @@ -526,5 +528,13 @@ namespace osu.Game.Screens.Play }; } } + + /// + /// Sets to , reserved for testing. + /// + public static void ResetNotificationLock() + { + muteWarningShownOnce = false; + } } } From 2bbf4ca4b59abf2a0e87b7c2481d922bacd773b5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Sep 2019 18:50:50 +0900 Subject: [PATCH 063/966] Update LabelledTextBox to use LabelledComponent --- .../UserInterface/TestSceneLabelledTextBox.cs | 32 ++++- .../LabelledComponents/LabelledTextBox.cs | 117 +++--------------- 2 files changed, 51 insertions(+), 98 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs index 395905a30d..f9a5369576 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs @@ -19,6 +19,36 @@ namespace osu.Game.Tests.Visual.UserInterface typeof(LabelledTextBox), }; + [TestCase(false)] + [TestCase(true)] + public void TestTextBox(bool hasDescription) => createTextBox(hasDescription); + + private void createTextBox(bool hasDescription = false) + { + AddStep("create component", () => + { + LabelledComponent component; + + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 500, + AutoSizeAxes = Axes.Y, + Child = component = new LabelledTextBox + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Label = "Testing text", + PlaceholderText = "This is definitely working as intended", + } + }; + + component.Label = "a sample component"; + component.Description = hasDescription ? "this text describes the component" : string.Empty; + }); + } + [BackgroundDependencyLoader] private void load() { @@ -32,7 +62,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Anchor = Anchor.Centre, Origin = Anchor.Centre, - LabelText = "Testing text", + Label = "Testing text", PlaceholderText = "This is definitely working as intended", } }; diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs index 1c53fc7088..992371fedf 100644 --- a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs @@ -3,127 +3,50 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osuTK.Graphics; namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents { - public class LabelledTextBox : CompositeDrawable + public class LabelledTextBox : LabelledComponent { - private const float label_container_width = 150; - private const float corner_radius = 15; - private const float default_height = 40; - private const float default_label_left_padding = 15; - private const float default_label_top_padding = 12; - private const float default_label_text_size = 16; - public event TextBox.OnCommitHandler OnCommit; + protected new OsuTextBox Component => (OsuTextBox)base.Component; + + public LabelledTextBox() + : base(false) + { + } + public bool ReadOnly { - get => textBox.ReadOnly; - set => textBox.ReadOnly = value; - } - - public string LabelText - { - get => label.Text; - set => label.Text = value; - } - - public float LabelTextSize - { - get => label.Font.Size; - set => label.Font = label.Font.With(size: value); + set => Component.ReadOnly = value; } public string PlaceholderText { - get => textBox.PlaceholderText; - set => textBox.PlaceholderText = value; + set => Component.PlaceholderText = value; } public string Text { - get => textBox.Text; - set => textBox.Text = value; - } - - public Color4 LabelTextColour - { - get => label.Colour; - set => label.Colour = value; - } - - private readonly OsuTextBox textBox; - private readonly OsuSpriteText label; - - public LabelledTextBox() - { - RelativeSizeAxes = Axes.X; - Height = default_height; - CornerRadius = corner_radius; - Masking = true; - - InternalChild = new Container - { - RelativeSizeAxes = Axes.Both, - CornerRadius = corner_radius, - Masking = true, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("1c2125"), - }, - new GridContainer - { - RelativeSizeAxes = Axes.X, - Height = default_height, - Content = new[] - { - new Drawable[] - { - label = new OsuSpriteText - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Padding = new MarginPadding { Left = default_label_left_padding, Top = default_label_top_padding }, - Colour = Color4.White, - Font = OsuFont.GetFont(size: default_label_text_size, weight: FontWeight.Bold), - }, - textBox = new OsuTextBox - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - RelativeSizeAxes = Axes.Both, - Height = 1, - CornerRadius = corner_radius, - }, - }, - }, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Absolute, label_container_width), - new Dimension() - } - } - } - }; - - textBox.OnCommit += OnCommit; + set => Component.Text = value; } [BackgroundDependencyLoader] private void load(OsuColour colours) { - textBox.BorderColour = colours.Blue; + Component.BorderColour = colours.Blue; } + + protected override Drawable CreateComponent() => new OsuTextBox + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + CornerRadius = CORNER_RADIUS, + }.With(t => t.OnCommit += (sender, newText) => OnCommit?.Invoke(sender, newText)); } } From 33c51d5178fc5191d143fd77407042e5dc6b6687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 20 Sep 2019 20:55:30 +0200 Subject: [PATCH 064/966] Extract parsing filter queries to class For the sake of testability without having to spin up visual tests, extract methods related to parsing filter queries from FilterControl to a static FilterQueryParser class. --- osu.Game/Screens/Select/FilterControl.cs | 131 +----------------- osu.Game/Screens/Select/FilterQueryParser.cs | 138 +++++++++++++++++++ 2 files changed, 139 insertions(+), 130 deletions(-) create mode 100644 osu.Game/Screens/Select/FilterQueryParser.cs diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index e3c23f7e22..91f1ca0307 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -16,8 +16,6 @@ using Container = osu.Framework.Graphics.Containers.Container; using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Rulesets; -using System.Text.RegularExpressions; -using osu.Game.Beatmaps; namespace osu.Game.Screens.Select { @@ -47,10 +45,7 @@ namespace osu.Game.Screens.Select Ruleset = ruleset.Value }; - applyQueries(criteria, ref query); - - criteria.SearchText = query; - + FilterQueryParser.ApplyQueries(criteria, query); return criteria; } @@ -181,129 +176,5 @@ namespace osu.Game.Screens.Select } private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria()); - - private static readonly Regex query_syntax_regex = new Regex( - @"\b(?stars|ar|dr|cs|divisor|length|objects|bpm|status)(?[=:><]+)(?\S*)", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private void applyQueries(FilterCriteria criteria, ref string query) - { - foreach (Match match in query_syntax_regex.Matches(query)) - { - var key = match.Groups["key"].Value.ToLower(); - var op = match.Groups["op"].Value; - var value = match.Groups["value"].Value; - - switch (key) - { - case "stars" when float.TryParse(value, out var stars): - updateCriteriaRange(ref criteria.StarDifficulty, op, stars); - break; - - case "ar" when float.TryParse(value, out var ar): - updateCriteriaRange(ref criteria.ApproachRate, op, ar); - break; - - case "dr" when float.TryParse(value, out var dr): - updateCriteriaRange(ref criteria.DrainRate, op, dr); - break; - - case "cs" when float.TryParse(value, out var cs): - updateCriteriaRange(ref criteria.CircleSize, op, cs); - break; - - case "bpm" when double.TryParse(value, out var bpm): - updateCriteriaRange(ref criteria.BPM, op, bpm); - break; - - case "length" when double.TryParse(value.TrimEnd('m', 's', 'h'), out var length): - var scale = - value.EndsWith("ms") ? 1 : - value.EndsWith("s") ? 1000 : - value.EndsWith("m") ? 60000 : - value.EndsWith("h") ? 3600000 : 1000; - - updateCriteriaRange(ref criteria.Length, op, length * scale, scale / 2.0); - break; - - case "divisor" when int.TryParse(value, out var divisor): - updateCriteriaRange(ref criteria.BeatDivisor, op, divisor); - break; - - case "status" when Enum.TryParse(value, true, out var statusValue): - updateCriteriaRange(ref criteria.OnlineStatus, op, statusValue); - break; - } - - query = query.Replace(match.ToString(), ""); - } - } - - private void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, float value, float tolerance = 0.05f) - { - updateCriteriaRange(ref range, op, value); - - switch (op) - { - case "=": - case ":": - range.Min = value - tolerance; - range.Max = value + tolerance; - break; - } - } - - private void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, double value, double tolerance = 0.05) - { - updateCriteriaRange(ref range, op, value); - - switch (op) - { - case "=": - case ":": - range.Min = value - tolerance; - range.Max = value + tolerance; - break; - } - } - - private void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, T value) - where T : struct, IComparable - { - switch (op) - { - default: - return; - - case "=": - case ":": - range.IsInclusive = true; - range.Min = value; - range.Max = value; - break; - - case ">": - range.IsInclusive = false; - range.Min = value; - break; - - case ">=": - case ">:": - range.IsInclusive = true; - range.Min = value; - break; - - case "<": - range.IsInclusive = false; - range.Max = value; - break; - - case "<=": - case "<:": - range.IsInclusive = true; - range.Max = value; - break; - } - } } } diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs new file mode 100644 index 0000000000..4e2b591fc9 --- /dev/null +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -0,0 +1,138 @@ +// 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.Text.RegularExpressions; +using osu.Game.Beatmaps; + +namespace osu.Game.Screens.Select +{ + internal static class FilterQueryParser + { + private static readonly Regex query_syntax_regex = new Regex( + @"\b(?stars|ar|dr|cs|divisor|length|objects|bpm|status)(?[=:><]+)(?\S*)", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + internal static void ApplyQueries(FilterCriteria criteria, string query) + { + foreach (Match match in query_syntax_regex.Matches(query)) + { + var key = match.Groups["key"].Value.ToLower(); + var op = match.Groups["op"].Value; + var value = match.Groups["value"].Value; + + switch (key) + { + case "stars" when float.TryParse(value, out var stars): + updateCriteriaRange(ref criteria.StarDifficulty, op, stars); + break; + + case "ar" when float.TryParse(value, out var ar): + updateCriteriaRange(ref criteria.ApproachRate, op, ar); + break; + + case "dr" when float.TryParse(value, out var dr): + updateCriteriaRange(ref criteria.DrainRate, op, dr); + break; + + case "cs" when float.TryParse(value, out var cs): + updateCriteriaRange(ref criteria.CircleSize, op, cs); + break; + + case "bpm" when double.TryParse(value, out var bpm): + updateCriteriaRange(ref criteria.BPM, op, bpm); + break; + + case "length" when double.TryParse(value.TrimEnd('m', 's', 'h'), out var length): + var scale = + value.EndsWith("ms") ? 1 : + value.EndsWith("s") ? 1000 : + value.EndsWith("m") ? 60000 : + value.EndsWith("h") ? 3600000 : 1000; + + updateCriteriaRange(ref criteria.Length, op, length * scale, scale / 2.0); + break; + + case "divisor" when int.TryParse(value, out var divisor): + updateCriteriaRange(ref criteria.BeatDivisor, op, divisor); + break; + + case "status" when Enum.TryParse(value, true, out var statusValue): + updateCriteriaRange(ref criteria.OnlineStatus, op, statusValue); + break; + } + + query = query.Replace(match.ToString(), ""); + } + + criteria.SearchText = query; + } + + private static void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, float value, float tolerance = 0.05f) + { + updateCriteriaRange(ref range, op, value); + + switch (op) + { + case "=": + case ":": + range.Min = value - tolerance; + range.Max = value + tolerance; + break; + } + } + + private static void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, double value, double tolerance = 0.05) + { + updateCriteriaRange(ref range, op, value); + + switch (op) + { + case "=": + case ":": + range.Min = value - tolerance; + range.Max = value + tolerance; + break; + } + } + + private static void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, T value) + where T : struct, IComparable + { + switch (op) + { + default: + return; + + case "=": + case ":": + range.IsInclusive = true; + range.Min = value; + range.Max = value; + break; + + case ">": + range.IsInclusive = false; + range.Min = value; + break; + + case ">=": + case ">:": + range.IsInclusive = true; + range.Min = value; + break; + + case "<": + range.IsInclusive = false; + range.Max = value; + break; + + case "<=": + case "<:": + range.IsInclusive = true; + range.Max = value; + break; + } + } + } +} From dddd94684bd233e1377211d086e0f47c736fb934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 20 Sep 2019 21:34:38 +0200 Subject: [PATCH 065/966] Split out lower and upper interval inclusivity A single IsInclusive field causes unexpected issues when trying to formulate a half-open interval query. Split out IsInclusive into two fields, Is{Lower,Upper}Inclusive and update usages accordingly. --- osu.Game/Screens/Select/FilterCriteria.cs | 10 ++++++---- osu.Game/Screens/Select/FilterQueryParser.cs | 10 +++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index a3fa1b10ca..97a7f12724 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Select if (comparison < 0) return false; - if (comparison == 0 && !IsInclusive) + if (comparison == 0 && !IsLowerInclusive) return false; } @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Select if (comparison > 0) return false; - if (comparison == 0 && !IsInclusive) + if (comparison == 0 && !IsUpperInclusive) return false; } @@ -73,12 +73,14 @@ namespace osu.Game.Screens.Select public T? Min; public T? Max; - public bool IsInclusive; + public bool IsLowerInclusive; + public bool IsUpperInclusive; public bool Equals(OptionalRange other) => Min.Equals(other.Min) && Max.Equals(other.Max) - && IsInclusive.Equals(other.IsInclusive); + && IsLowerInclusive.Equals(other.IsLowerInclusive) + && IsUpperInclusive.Equals(other.IsUpperInclusive); } } } diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 4e2b591fc9..800f1afd03 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -106,30 +106,30 @@ namespace osu.Game.Screens.Select case "=": case ":": - range.IsInclusive = true; + range.IsLowerInclusive = range.IsUpperInclusive = true; range.Min = value; range.Max = value; break; case ">": - range.IsInclusive = false; + range.IsLowerInclusive = false; range.Min = value; break; case ">=": case ">:": - range.IsInclusive = true; + range.IsLowerInclusive = true; range.Min = value; break; case "<": - range.IsInclusive = false; + range.IsUpperInclusive = false; range.Max = value; break; case "<=": case "<:": - range.IsInclusive = true; + range.IsUpperInclusive = true; range.Max = value; break; } From f5f5094611257f50fc778becf402105868e9757f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 20 Sep 2019 22:10:46 +0200 Subject: [PATCH 066/966] Take culture into account when parsing filters Culture was not taken into account when parsing filters, which meant that in cultures that use the comma (,) as a decimal delimiter, it would conflict with the comma used to delimit search criteria. To remove any ambiguity, introduce local helper functions that allow the decimal point to be utilised, using the invariant culture. This also matches stable behaviour. The decision to not reuse osu.Game.Beatmaps.Formats.Parsing was deliberate due to differing semantics (it's not really sane to throw exceptions on receiving user-facing input). --- osu.Game/Screens/Select/FilterQueryParser.cs | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 800f1afd03..d6d19c8650 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Globalization; using System.Text.RegularExpressions; using osu.Game.Beatmaps; @@ -23,27 +24,27 @@ namespace osu.Game.Screens.Select switch (key) { - case "stars" when float.TryParse(value, out var stars): + case "stars" when parseFloatWithPoint(value, out var stars): updateCriteriaRange(ref criteria.StarDifficulty, op, stars); break; - case "ar" when float.TryParse(value, out var ar): + case "ar" when parseFloatWithPoint(value, out var ar): updateCriteriaRange(ref criteria.ApproachRate, op, ar); break; - case "dr" when float.TryParse(value, out var dr): + case "dr" when parseFloatWithPoint(value, out var dr): updateCriteriaRange(ref criteria.DrainRate, op, dr); break; - case "cs" when float.TryParse(value, out var cs): + case "cs" when parseFloatWithPoint(value, out var cs): updateCriteriaRange(ref criteria.CircleSize, op, cs); break; - case "bpm" when double.TryParse(value, out var bpm): + case "bpm" when parseDoubleWithPoint(value, out var bpm): updateCriteriaRange(ref criteria.BPM, op, bpm); break; - case "length" when double.TryParse(value.TrimEnd('m', 's', 'h'), out var length): + case "length" when parseDoubleWithPoint(value.TrimEnd('m', 's', 'h'), out var length): var scale = value.EndsWith("ms") ? 1 : value.EndsWith("s") ? 1000 : @@ -53,7 +54,7 @@ namespace osu.Game.Screens.Select updateCriteriaRange(ref criteria.Length, op, length * scale, scale / 2.0); break; - case "divisor" when int.TryParse(value, out var divisor): + case "divisor" when parseInt(value, out var divisor): updateCriteriaRange(ref criteria.BeatDivisor, op, divisor); break; @@ -68,6 +69,15 @@ namespace osu.Game.Screens.Select criteria.SearchText = query; } + private static bool parseFloatWithPoint(string value, out float result) => + float.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result); + + private static bool parseDoubleWithPoint(string value, out double result) => + double.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result); + + private static bool parseInt(string value, out int result) => + int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result); + private static void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, float value, float tolerance = 0.05f) { updateCriteriaRange(ref range, op, value); From d11d932a8747273f56f4128dbcf8b31bd6a329c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 20 Sep 2019 22:19:45 +0200 Subject: [PATCH 067/966] Add filter parsing tests Introduce unit tests covering parsing for the originally introduced filtering features. The introduced improvements (lower and upper interval and decimal point support) also tested. --- .../Filtering/FilterQueryParserTest.cs | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs new file mode 100644 index 0000000000..f98ad1fc43 --- /dev/null +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -0,0 +1,129 @@ +// 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 NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Screens.Select; + +namespace osu.Game.Tests.NonVisual.Filtering +{ + [TestFixture] + public class FilterQueryParserTest + { + [Test] + public void TestApplyQueriesBareWords() + { + const string query = "looking for a beatmap"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("looking for a beatmap", filterCriteria.SearchText); + Assert.AreEqual(4, filterCriteria.SearchTerms.Length); + } + + [Test] + public void TestApplyStarQueries() + { + const string query = "stars<4 easy"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("easy", filterCriteria.SearchText.Trim()); + Assert.AreEqual(1, filterCriteria.SearchTerms.Length); + Assert.AreEqual(4.0f, filterCriteria.StarDifficulty.Max); + Assert.IsFalse(filterCriteria.StarDifficulty.IsUpperInclusive); + Assert.IsNull(filterCriteria.StarDifficulty.Min); + } + + [Test] + public void TestApplyApproachRateQueries() + { + const string query = "ar>=9 difficult"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("difficult", filterCriteria.SearchText.Trim()); + Assert.AreEqual(1, filterCriteria.SearchTerms.Length); + Assert.AreEqual(9.0f, filterCriteria.ApproachRate.Min); + Assert.IsTrue(filterCriteria.ApproachRate.IsLowerInclusive); + Assert.IsNull(filterCriteria.ApproachRate.Max); + } + + [Test] + public void TestApplyDrainRateQueries() + { + const string query = "dr>2 quite specific dr<:6"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("quite specific", filterCriteria.SearchText.Trim()); + Assert.AreEqual(2, filterCriteria.SearchTerms.Length); + Assert.AreEqual(2.0f, filterCriteria.DrainRate.Min); + Assert.IsFalse(filterCriteria.DrainRate.IsLowerInclusive); + Assert.AreEqual(6.0f, filterCriteria.DrainRate.Max); + Assert.IsTrue(filterCriteria.DrainRate.IsUpperInclusive); + } + + [Test] + public void TestApplyBPMQueries() + { + const string query = "bpm>:200 gotta go fast"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("gotta go fast", filterCriteria.SearchText.Trim()); + Assert.AreEqual(3, filterCriteria.SearchTerms.Length); + Assert.AreEqual(200d, filterCriteria.BPM.Min); + Assert.IsTrue(filterCriteria.BPM.IsLowerInclusive); + Assert.IsNull(filterCriteria.BPM.Max); + } + + private static object[] lengthQueryExamples = + { + new object[] { "6ms", TimeSpan.FromMilliseconds(6), TimeSpan.FromMilliseconds(1) }, + new object[] { "23s", TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(1) }, + new object[] { "9m", TimeSpan.FromMinutes(9), TimeSpan.FromMinutes(1) }, + new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1) }, + new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1) }, + }; + + [Test] + [TestCaseSource(nameof(lengthQueryExamples))] + public void TestApplyLengthQueries(string lengthQuery, TimeSpan expectedLength, TimeSpan scale) + { + string query = $"length={lengthQuery} time"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("time", filterCriteria.SearchText.Trim()); + Assert.AreEqual(1, filterCriteria.SearchTerms.Length); + Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); + Assert.IsTrue(filterCriteria.Length.IsLowerInclusive); + Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); + Assert.IsTrue(filterCriteria.Length.IsUpperInclusive); + } + + [Test] + public void TestApplyDivisorQueries() + { + const string query = "that's a time signature alright! divisor:12"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("that's a time signature alright!", filterCriteria.SearchText.Trim()); + Assert.AreEqual(5, filterCriteria.SearchTerms.Length); + Assert.AreEqual(12, filterCriteria.BeatDivisor.Min); + Assert.IsTrue(filterCriteria.BeatDivisor.IsLowerInclusive); + Assert.AreEqual(12, filterCriteria.BeatDivisor.Max); + Assert.IsTrue(filterCriteria.BeatDivisor.IsUpperInclusive); + } + + [Test] + public void TestApplyStatusQueries() + { + const string query = "I want the pp status=ranked"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("I want the pp", filterCriteria.SearchText.Trim()); + Assert.AreEqual(4, filterCriteria.SearchTerms.Length); + Assert.AreEqual(BeatmapSetOnlineStatus.Ranked, filterCriteria.OnlineStatus.Min); + Assert.IsTrue(filterCriteria.OnlineStatus.IsLowerInclusive); + Assert.AreEqual(BeatmapSetOnlineStatus.Ranked, filterCriteria.OnlineStatus.Max); + Assert.IsTrue(filterCriteria.OnlineStatus.IsUpperInclusive); + } + } +} From 41569fd2b63f82aa5a19f4f026120d0d2f2717ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 20 Sep 2019 22:48:30 +0200 Subject: [PATCH 068/966] Add filter evaluating unit tests Introduce unit tests covering the actual evaluation of filters for beatmaps. Partially covers most scenarios. --- .../NonVisual/Filtering/FilterMatchingTest.cs | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs new file mode 100644 index 0000000000..24e735310d --- /dev/null +++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs @@ -0,0 +1,136 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Screens.Select; +using osu.Game.Screens.Select.Carousel; + +namespace osu.Game.Tests.NonVisual.Filtering +{ + [TestFixture] + public class FilterMatchingTest + { + private readonly BeatmapInfo exampleBeatmapInfo = new BeatmapInfo + { + Ruleset = new RulesetInfo { ID = 5 }, + StarDifficulty = 4.0d, + BaseDifficulty = new BeatmapDifficulty + { + ApproachRate = 5.0f, + DrainRate = 3.0f, + CircleSize = 2.0f, + }, + Metadata = new BeatmapMetadata + { + Artist = "The Artist", + ArtistUnicode = "The Artist", + Title = "Title goes here", + TitleUnicode = "Title goes here", + AuthorString = "Author", + Source = "unit tests", + Tags = "look for tags too", + }, + Version = "version as well", + Length = 2500, + BPM = 160, + BeatDivisor = 12, + Status = BeatmapSetOnlineStatus.Loved + }; + + [Test] + public void TestCriteriaMatchingNoRuleset() + { + var criteria = new FilterCriteria(); + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.IsFalse(carouselItem.Filtered.Value); + } + + [Test] + public void TestCriteriaMatchingSpecificRuleset() + { + var criteria = new FilterCriteria + { + Ruleset = new RulesetInfo { ID = 6 } + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.IsTrue(carouselItem.Filtered.Value); + } + + [Test] + public void TestCriteriaMatchingConvertedBeatmaps() + { + var criteria = new FilterCriteria + { + Ruleset = new RulesetInfo { ID = 6 }, + AllowConvertedBeatmaps = true + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.IsFalse(carouselItem.Filtered.Value); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void TestCriteriaMatchingRangeMin(bool inclusive) + { + var criteria = new FilterCriteria + { + Ruleset = new RulesetInfo { ID = 6 }, + AllowConvertedBeatmaps = true, + ApproachRate = new FilterCriteria.OptionalRange + { + IsLowerInclusive = inclusive, + Min = 5.0f + } + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.AreEqual(!inclusive, carouselItem.Filtered.Value); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void TestCriteriaMatchingRangeMax(bool inclusive) + { + var criteria = new FilterCriteria + { + Ruleset = new RulesetInfo { ID = 6 }, + AllowConvertedBeatmaps = true, + BPM = new FilterCriteria.OptionalRange + { + IsUpperInclusive = inclusive, + Max = 160d + } + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.AreEqual(!inclusive, carouselItem.Filtered.Value); + } + + [Test] + [TestCase("artist", false)] + [TestCase("artist title author", false)] + [TestCase("an artist", true)] + [TestCase("tags too", false)] + [TestCase("version", false)] + [TestCase("an auteur", true)] + public void TestCriteriaMatchingTerms(string terms, bool filtered) + { + var criteria = new FilterCriteria + { + Ruleset = new RulesetInfo { ID = 6 }, + AllowConvertedBeatmaps = true, + SearchText = terms + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.AreEqual(filtered, carouselItem.Filtered.Value); + } + } +} From 51509f6be03523771e61269311086d6fdb49c7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 20 Sep 2019 23:06:20 +0200 Subject: [PATCH 069/966] Add filter steps to carousel visual test Just a couple of steps for added coverage in visual tests. Very on-the-surface, the unit tests are supposed to cover the gory details. --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 6669ec7da3..71399106f4 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -242,6 +242,21 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false)); AddAssert("Selection is non-null", () => currentSelection != null); + + setSelected(1, 3); + AddStep("Apply a range filter", () => carousel.Filter(new FilterCriteria + { + SearchText = "#3", + StarDifficulty = new FilterCriteria.OptionalRange + { + Min = 2, + Max = 5.5, + IsLowerInclusive = true + } + }, false)); + checkSelected(3, 2); + + AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false)); } /// From b262ba13cd5d2ea1c9a908bd542f7c28758299fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Sep 2019 23:16:23 +0200 Subject: [PATCH 070/966] Add creator= and artist= filters To match stable, add creator= and artist= filters to the beatmap carousel on song select screen. Contrary to stable, this implementation supports phrase queries with spaces within using double quotes. The quote handling is not entirely correct (can't nest), but quotes should rarely happen within names, and it is an edge case of an edge case - leaving best-effort as is. Test coverage also included. --- .../NonVisual/Filtering/FilterMatchingTest.cs | 71 ++++++++++++++++++- .../Filtering/FilterQueryParserTest.cs | 44 ++++++++++++ .../Select/Carousel/CarouselBeatmap.cs | 4 ++ osu.Game/Screens/Select/FilterCriteria.cs | 21 ++++++ osu.Game/Screens/Select/FilterQueryParser.cs | 21 +++++- 5 files changed, 157 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs index 24e735310d..30686cb947 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterMatchingTest.cs @@ -12,7 +12,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [TestFixture] public class FilterMatchingTest { - private readonly BeatmapInfo exampleBeatmapInfo = new BeatmapInfo + private BeatmapInfo getExampleBeatmap() => new BeatmapInfo { Ruleset = new RulesetInfo { ID = 5 }, StarDifficulty = 4.0d, @@ -25,10 +25,10 @@ namespace osu.Game.Tests.NonVisual.Filtering Metadata = new BeatmapMetadata { Artist = "The Artist", - ArtistUnicode = "The Artist", + ArtistUnicode = "check unicode too", Title = "Title goes here", TitleUnicode = "Title goes here", - AuthorString = "Author", + AuthorString = "The Author", Source = "unit tests", Tags = "look for tags too", }, @@ -42,6 +42,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestCriteriaMatchingNoRuleset() { + var exampleBeatmapInfo = getExampleBeatmap(); var criteria = new FilterCriteria(); var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); carouselItem.Filter(criteria); @@ -51,6 +52,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestCriteriaMatchingSpecificRuleset() { + var exampleBeatmapInfo = getExampleBeatmap(); var criteria = new FilterCriteria { Ruleset = new RulesetInfo { ID = 6 } @@ -63,6 +65,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestCriteriaMatchingConvertedBeatmaps() { + var exampleBeatmapInfo = getExampleBeatmap(); var criteria = new FilterCriteria { Ruleset = new RulesetInfo { ID = 6 }, @@ -78,6 +81,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [TestCase(false)] public void TestCriteriaMatchingRangeMin(bool inclusive) { + var exampleBeatmapInfo = getExampleBeatmap(); var criteria = new FilterCriteria { Ruleset = new RulesetInfo { ID = 6 }, @@ -98,6 +102,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [TestCase(false)] public void TestCriteriaMatchingRangeMax(bool inclusive) { + var exampleBeatmapInfo = getExampleBeatmap(); var criteria = new FilterCriteria { Ruleset = new RulesetInfo { ID = 6 }, @@ -122,6 +127,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [TestCase("an auteur", true)] public void TestCriteriaMatchingTerms(string terms, bool filtered) { + var exampleBeatmapInfo = getExampleBeatmap(); var criteria = new FilterCriteria { Ruleset = new RulesetInfo { ID = 6 }, @@ -132,5 +138,64 @@ namespace osu.Game.Tests.NonVisual.Filtering carouselItem.Filter(criteria); Assert.AreEqual(filtered, carouselItem.Filtered.Value); } + + [Test] + [TestCase("", false)] + [TestCase("The", false)] + [TestCase("THE", false)] + [TestCase("author", false)] + [TestCase("the author", false)] + [TestCase("the author AND then something else", true)] + [TestCase("unknown", true)] + public void TestCriteriaMatchingCreator(string creatorName, bool filtered) + { + var exampleBeatmapInfo = getExampleBeatmap(); + var criteria = new FilterCriteria + { + Creator = new FilterCriteria.OptionalTextFilter { SearchTerm = creatorName } + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.AreEqual(filtered, carouselItem.Filtered.Value); + } + + [Test] + [TestCase("", false)] + [TestCase("The", false)] + [TestCase("THE", false)] + [TestCase("artist", false)] + [TestCase("the artist", false)] + [TestCase("the artist AND then something else", true)] + [TestCase("unicode too", false)] + [TestCase("unknown", true)] + public void TestCriteriaMatchingArtist(string artistName, bool filtered) + { + var exampleBeatmapInfo = getExampleBeatmap(); + var criteria = new FilterCriteria + { + Artist = new FilterCriteria.OptionalTextFilter { SearchTerm = artistName } + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.AreEqual(filtered, carouselItem.Filtered.Value); + } + + [Test] + [TestCase("", false)] + [TestCase("artist", false)] + [TestCase("unknown", true)] + public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered) + { + var exampleBeatmapInfo = getExampleBeatmap(); + exampleBeatmapInfo.Metadata.ArtistUnicode = null; + + var criteria = new FilterCriteria + { + Artist = new FilterCriteria.OptionalTextFilter { SearchTerm = artistName } + }; + var carouselItem = new CarouselBeatmap(exampleBeatmapInfo); + carouselItem.Filter(criteria); + Assert.AreEqual(filtered, carouselItem.Filtered.Value); + } } } diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index f98ad1fc43..daab690a84 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -125,5 +125,49 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.AreEqual(BeatmapSetOnlineStatus.Ranked, filterCriteria.OnlineStatus.Max); Assert.IsTrue(filterCriteria.OnlineStatus.IsUpperInclusive); } + + [Test] + public void TestApplyCreatorQueries() + { + const string query = "beatmap specifically by creator=my_fav"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("beatmap specifically by", filterCriteria.SearchText.Trim()); + Assert.AreEqual(3, filterCriteria.SearchTerms.Length); + Assert.AreEqual("my_fav", filterCriteria.Creator.SearchTerm); + } + + [Test] + public void TestApplyArtistQueries() + { + const string query = "find me songs by artist=singer please"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("find me songs by please", filterCriteria.SearchText.Trim()); + Assert.AreEqual(5, filterCriteria.SearchTerms.Length); + Assert.AreEqual("singer", filterCriteria.Artist.SearchTerm); + } + + [Test] + public void TestApplyArtistQueriesWithSpaces() + { + const string query = "really like artist=\"name with space\" yes"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("really like yes", filterCriteria.SearchText.Trim()); + Assert.AreEqual(3, filterCriteria.SearchTerms.Length); + Assert.AreEqual("name with space", filterCriteria.Artist.SearchTerm); + } + + [Test] + public void TestApplyArtistQueriesOneDoubleQuote() + { + const string query = "weird artist=double\"quote"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual("weird", filterCriteria.SearchText.Trim()); + Assert.AreEqual(1, filterCriteria.SearchTerms.Length); + Assert.AreEqual("double\"quote", filterCriteria.Artist.SearchTerm); + } } } diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 9cc84c8bdd..6c3c9d20f3 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -39,6 +39,10 @@ namespace osu.Game.Screens.Select.Carousel match &= criteria.BeatDivisor.IsInRange(Beatmap.BeatDivisor); match &= criteria.OnlineStatus.IsInRange(Beatmap.Status); + match &= criteria.Creator.Matches(Beatmap.Metadata.AuthorString); + match &= criteria.Artist.Matches(Beatmap.Metadata.Artist) || + criteria.Artist.Matches(Beatmap.Metadata.ArtistUnicode); + if (match) foreach (var criteriaTerm in criteria.SearchTerms) match &= diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index 97a7f12724..c2cbac905e 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -23,6 +23,8 @@ namespace osu.Game.Screens.Select public OptionalRange BPM; public OptionalRange BeatDivisor; public OptionalRange OnlineStatus; + public OptionalTextFilter Creator; + public OptionalTextFilter Artist; public string[] SearchTerms = Array.Empty(); @@ -82,5 +84,24 @@ namespace osu.Game.Screens.Select && IsLowerInclusive.Equals(other.IsLowerInclusive) && IsUpperInclusive.Equals(other.IsUpperInclusive); } + + public struct OptionalTextFilter : IEquatable + { + public bool Matches(string value) + { + if (string.IsNullOrEmpty(SearchTerm)) + return true; + + // search term is guaranteed to be non-empty, so if the string we're comparing is empty, it's not matching + if (string.IsNullOrEmpty(value)) + return false; + + return value.IndexOf(SearchTerm, StringComparison.InvariantCultureIgnoreCase) >= 0; + } + + public string SearchTerm; + + public bool Equals(OptionalTextFilter other) => SearchTerm?.Equals(other.SearchTerm) ?? true; + } } } diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index d6d19c8650..b9281c5d6f 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Select internal static class FilterQueryParser { private static readonly Regex query_syntax_regex = new Regex( - @"\b(?stars|ar|dr|cs|divisor|length|objects|bpm|status)(?[=:><]+)(?\S*)", + @"\b(?stars|ar|dr|cs|divisor|length|objects|bpm|status|creator|artist)(?[=:><]+)(?("".*"")|(\S*))", RegexOptions.Compiled | RegexOptions.IgnoreCase); internal static void ApplyQueries(FilterCriteria criteria, string query) @@ -61,6 +61,14 @@ namespace osu.Game.Screens.Select case "status" when Enum.TryParse(value, true, out var statusValue): updateCriteriaRange(ref criteria.OnlineStatus, op, statusValue); break; + + case "creator": + updateCriteriaText(ref criteria.Creator, op, value); + break; + + case "artist": + updateCriteriaText(ref criteria.Artist, op, value); + break; } query = query.Replace(match.ToString(), ""); @@ -78,6 +86,17 @@ namespace osu.Game.Screens.Select private static bool parseInt(string value, out int result) => int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result); + private static void updateCriteriaText(ref FilterCriteria.OptionalTextFilter textFilter, string op, string value) + { + switch (op) + { + case "=": + case ":": + textFilter.SearchTerm = value.Trim('"'); + break; + } + } + private static void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, float value, float tolerance = 0.05f) { updateCriteriaRange(ref range, op, value); From 70842f71f4b54484ea1ef22c19379950c2a01a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Sep 2019 00:11:13 +0200 Subject: [PATCH 071/966] Fix floating point handling in filter intervals Due to floating-point rounding and representation errors, filters could wrongly display results incongruous with the wedge display text (ie. a beatmap with the BPM of 139.99999 would be displayed as having 140 BPM and also pass the bpm<140 filter). Apply tolerance when parsing floating-point constraints. The tolerance chosen is half of what the UI displays for the particular values (so for example half of 0.1 for AR/DR/CS, 0.01 for stars, etc.) Tests updated accordingly. --- .../Filtering/FilterQueryParserTest.cs | 35 ++++++++---- osu.Game/Screens/Select/FilterQueryParser.cs | 56 ++++++++++++++++--- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index daab690a84..9869ddde41 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -21,6 +21,16 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.AreEqual(4, filterCriteria.SearchTerms.Length); } + /* + * The following tests have been written a bit strangely (they don't check exact + * bound equality with what the filter says). + * This is to account for floating-point arithmetic issues. + * For example, specifying a bpm<140 filter would previously match beatmaps with BPM + * of 139.99999, which would be displayed in the UI as 140. + * Due to this the tests check the last tick inside the range and the first tick + * outside of the range. + */ + [Test] public void TestApplyStarQueries() { @@ -29,8 +39,9 @@ namespace osu.Game.Tests.NonVisual.Filtering FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual("easy", filterCriteria.SearchText.Trim()); Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.AreEqual(4.0f, filterCriteria.StarDifficulty.Max); - Assert.IsFalse(filterCriteria.StarDifficulty.IsUpperInclusive); + Assert.IsNotNull(filterCriteria.StarDifficulty.Max); + Assert.Greater(filterCriteria.StarDifficulty.Max, 3.99d); + Assert.Less(filterCriteria.StarDifficulty.Max, 4.00d); Assert.IsNull(filterCriteria.StarDifficulty.Min); } @@ -42,8 +53,9 @@ namespace osu.Game.Tests.NonVisual.Filtering FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual("difficult", filterCriteria.SearchText.Trim()); Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.AreEqual(9.0f, filterCriteria.ApproachRate.Min); - Assert.IsTrue(filterCriteria.ApproachRate.IsLowerInclusive); + Assert.IsNotNull(filterCriteria.ApproachRate.Min); + Assert.Greater(filterCriteria.ApproachRate.Min, 8.9f); + Assert.Less(filterCriteria.ApproachRate.Min, 9.0f); Assert.IsNull(filterCriteria.ApproachRate.Max); } @@ -55,10 +67,10 @@ namespace osu.Game.Tests.NonVisual.Filtering FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual("quite specific", filterCriteria.SearchText.Trim()); Assert.AreEqual(2, filterCriteria.SearchTerms.Length); - Assert.AreEqual(2.0f, filterCriteria.DrainRate.Min); - Assert.IsFalse(filterCriteria.DrainRate.IsLowerInclusive); - Assert.AreEqual(6.0f, filterCriteria.DrainRate.Max); - Assert.IsTrue(filterCriteria.DrainRate.IsUpperInclusive); + Assert.Greater(filterCriteria.DrainRate.Min, 2.0f); + Assert.Less(filterCriteria.DrainRate.Min, 2.1f); + Assert.Greater(filterCriteria.DrainRate.Max, 6.0f); + Assert.Less(filterCriteria.DrainRate.Min, 6.1f); } [Test] @@ -69,8 +81,9 @@ namespace osu.Game.Tests.NonVisual.Filtering FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual("gotta go fast", filterCriteria.SearchText.Trim()); Assert.AreEqual(3, filterCriteria.SearchTerms.Length); - Assert.AreEqual(200d, filterCriteria.BPM.Min); - Assert.IsTrue(filterCriteria.BPM.IsLowerInclusive); + Assert.IsNotNull(filterCriteria.BPM.Min); + Assert.Greater(filterCriteria.BPM.Min, 199.99d); + Assert.Less(filterCriteria.BPM.Min, 200.00d); Assert.IsNull(filterCriteria.BPM.Max); } @@ -93,9 +106,7 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.AreEqual("time", filterCriteria.SearchText.Trim()); Assert.AreEqual(1, filterCriteria.SearchTerms.Length); Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); - Assert.IsTrue(filterCriteria.Length.IsLowerInclusive); Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); - Assert.IsTrue(filterCriteria.Length.IsUpperInclusive); } [Test] diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index b9281c5d6f..3ee704201e 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -25,23 +25,23 @@ namespace osu.Game.Screens.Select switch (key) { case "stars" when parseFloatWithPoint(value, out var stars): - updateCriteriaRange(ref criteria.StarDifficulty, op, stars); + updateCriteriaRange(ref criteria.StarDifficulty, op, stars, 0.01f / 2); break; case "ar" when parseFloatWithPoint(value, out var ar): - updateCriteriaRange(ref criteria.ApproachRate, op, ar); + updateCriteriaRange(ref criteria.ApproachRate, op, ar, 0.1f / 2); break; case "dr" when parseFloatWithPoint(value, out var dr): - updateCriteriaRange(ref criteria.DrainRate, op, dr); + updateCriteriaRange(ref criteria.DrainRate, op, dr, 0.1f / 2); break; case "cs" when parseFloatWithPoint(value, out var cs): - updateCriteriaRange(ref criteria.CircleSize, op, cs); + updateCriteriaRange(ref criteria.CircleSize, op, cs, 0.1f / 2); break; case "bpm" when parseDoubleWithPoint(value, out var bpm): - updateCriteriaRange(ref criteria.BPM, op, bpm); + updateCriteriaRange(ref criteria.BPM, op, bpm, 0.01d / 2); break; case "length" when parseDoubleWithPoint(value.TrimEnd('m', 's', 'h'), out var length): @@ -99,29 +99,67 @@ namespace osu.Game.Screens.Select private static void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, float value, float tolerance = 0.05f) { - updateCriteriaRange(ref range, op, value); - switch (op) { + default: + return; + case "=": case ":": range.Min = value - tolerance; range.Max = value + tolerance; break; + + case ">": + range.Min = value + tolerance; + break; + + case ">=": + case ">:": + range.Min = value - tolerance; + break; + + case "<": + range.Max = value - tolerance; + break; + + case "<=": + case "<:": + range.Max = value + tolerance; + break; } } private static void updateCriteriaRange(ref FilterCriteria.OptionalRange range, string op, double value, double tolerance = 0.05) { - updateCriteriaRange(ref range, op, value); - switch (op) { + default: + return; + case "=": case ":": range.Min = value - tolerance; range.Max = value + tolerance; break; + + case ">": + range.Min = value + tolerance; + break; + + case ">=": + case ">:": + range.Min = value - tolerance; + break; + + case "<": + range.Max = value - tolerance; + break; + + case "<=": + case "<:": + range.Max = value + tolerance; + break; } } From fc1d49631a934437b24ccab3014aa31f2c06f579 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Sep 2019 20:30:58 +0900 Subject: [PATCH 072/966] Allow top-level menu key pressed to progress the osu! logo --- osu.Game/Screens/Menu/Button.cs | 7 ++++--- osu.Game/Screens/Menu/ButtonSystem.cs | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index 1bf25a2504..ffeadb96c7 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -31,6 +31,8 @@ namespace osu.Game.Screens.Menu { public event Action StateChanged; + public readonly Key TriggerKey; + private readonly Container iconText; private readonly Container box; private readonly Box boxHoverLayer; @@ -43,7 +45,6 @@ namespace osu.Game.Screens.Menu public ButtonSystemState VisibleState = ButtonSystemState.TopLevel; private readonly Action clickAction; - private readonly Key triggerKey; private SampleChannel sampleClick; private SampleChannel sampleHover; @@ -53,7 +54,7 @@ namespace osu.Game.Screens.Menu { this.sampleName = sampleName; this.clickAction = clickAction; - this.triggerKey = triggerKey; + TriggerKey = triggerKey; AutoSizeAxes = Axes.Both; Alpha = 0; @@ -210,7 +211,7 @@ namespace osu.Game.Screens.Menu if (e.Repeat || e.ControlPressed || e.ShiftPressed || e.AltPressed) return false; - if (triggerKey == e.Key && triggerKey != Key.Unknown) + if (TriggerKey == e.Key && TriggerKey != Key.Unknown) { trigger(); return true; diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 1a3e1213b4..0dee478a4c 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Threading; @@ -180,6 +181,20 @@ namespace osu.Game.Screens.Menu State = ButtonSystemState.Initial; } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (State == ButtonSystemState.Initial) + { + if (buttonsTopLevel.Any(b => e.PressedKeys.Contains(b.TriggerKey))) + { + logo.Click(); + return true; + } + } + + return base.OnKeyDown(e); + } + public bool OnPressed(GlobalAction action) { switch (action) From e5b14ce74de34d23ce42913a3c24152d75022866 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Sep 2019 21:42:32 +0900 Subject: [PATCH 073/966] Add null check for safety Co-Authored-By: Salman Ahmed --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 0dee478a4c..7ac6b5c696 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -187,7 +187,7 @@ namespace osu.Game.Screens.Menu { if (buttonsTopLevel.Any(b => e.PressedKeys.Contains(b.TriggerKey))) { - logo.Click(); + logo?.Click(); return true; } } From 3b52e7c72408555fbf6d42d988033ef30bac7f0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Sep 2019 02:10:04 +0900 Subject: [PATCH 074/966] Add boilerplate logic --- .../Screens/TestSceneSetupScreen.cs | 17 +++++++++++++++++ osu.Game.Tournament/Screens/SetupScreen.cs | 9 +++++++++ osu.Game.Tournament/TournamentSceneManager.cs | 2 ++ 3 files changed, 28 insertions(+) create mode 100644 osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs create mode 100644 osu.Game.Tournament/Screens/SetupScreen.cs diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs new file mode 100644 index 0000000000..650b4c5412 --- /dev/null +++ b/osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs @@ -0,0 +1,17 @@ +// 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.Allocation; +using osu.Game.Tournament.Screens; + +namespace osu.Game.Tournament.Tests.Screens +{ + public class TestSceneSetupScreen : TournamentTestScene + { + [BackgroundDependencyLoader] + private void load() + { + Add(new SetupScreen()); + } + } +} diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs new file mode 100644 index 0000000000..a5e0e5927a --- /dev/null +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -0,0 +1,9 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Tournament.Screens +{ + public class SetupScreen : TournamentScreen + { + } +} diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs index 4c255be463..b1384023d3 100644 --- a/osu.Game.Tournament/TournamentSceneManager.cs +++ b/osu.Game.Tournament/TournamentSceneManager.cs @@ -106,6 +106,8 @@ namespace osu.Game.Tournament Direction = FillDirection.Vertical, Children = new Drawable[] { + new OsuButton { RelativeSizeAxes = Axes.X, Text = "Setup", Action = () => SetScreen(typeof(SetupScreen)) }, + new Container { RelativeSizeAxes = Axes.X, Height = 50 }, new OsuButton { RelativeSizeAxes = Axes.X, Text = "Team Editor", Action = () => SetScreen(typeof(TeamEditorScreen)) }, new OsuButton { RelativeSizeAxes = Axes.X, Text = "Rounds Editor", Action = () => SetScreen(typeof(RoundEditorScreen)) }, new OsuButton { RelativeSizeAxes = Axes.X, Text = "Bracket Editor", Action = () => SetScreen(typeof(LadderEditorScreen)) }, From 47a89231ad3da90ca774fb524a75cd61c68a4bbd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Sep 2019 04:15:02 +0900 Subject: [PATCH 075/966] Read from (and allow reloading) IPC source --- osu.Game.Tournament/IPC/FileBasedIPC.cs | 186 +++++++++++---------- osu.Game.Tournament/Screens/SetupScreen.cs | 15 ++ 2 files changed, 117 insertions(+), 84 deletions(-) diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs index 4fd858bd12..e05d96e098 100644 --- a/osu.Game.Tournament/IPC/FileBasedIPC.cs +++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Platform.Windows; +using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; using osu.Game.Online.API; @@ -26,103 +27,120 @@ namespace osu.Game.Tournament.IPC [Resolved] protected RulesetStore Rulesets { get; private set; } + [Resolved] + private GameHost host { get; set; } + + [Resolved] + private LadderInfo ladder { get; set; } + private int lastBeatmapId; + private ScheduledDelegate scheduled; + + public Storage Storage { get; private set; } [BackgroundDependencyLoader] - private void load(LadderInfo ladder, GameHost host) + private void load() { - StableStorage stable; + LocateStableStorage(); + } + + public Storage LocateStableStorage() + { + scheduled?.Cancel(); + + Storage = null; try { - stable = new StableStorage(host as DesktopGameHost); + Storage = new StableStorage(host as DesktopGameHost); + + const string file_ipc_filename = "ipc.txt"; + const string file_ipc_state_filename = "ipc-state.txt"; + const string file_ipc_scores_filename = "ipc-scores.txt"; + const string file_ipc_channel_filename = "ipc-channel.txt"; + + if (Storage.Exists(file_ipc_filename)) + scheduled = Scheduler.AddDelayed(delegate + { + try + { + using (var stream = Storage.GetStream(file_ipc_filename)) + using (var sr = new StreamReader(stream)) + { + var beatmapId = int.Parse(sr.ReadLine()); + var mods = int.Parse(sr.ReadLine()); + + if (lastBeatmapId != beatmapId) + { + lastBeatmapId = beatmapId; + + var existing = ladder.CurrentMatch.Value?.Round.Value?.Beatmaps.FirstOrDefault(b => b.ID == beatmapId && b.BeatmapInfo != null); + + if (existing != null) + Beatmap.Value = existing.BeatmapInfo; + else + { + var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = beatmapId }); + req.Success += b => Beatmap.Value = b.ToBeatmap(Rulesets); + API.Queue(req); + } + } + + Mods.Value = (LegacyMods)mods; + } + } + catch + { + // file might be in use. + } + + try + { + using (var stream = Storage.GetStream(file_ipc_channel_filename)) + using (var sr = new StreamReader(stream)) + { + ChatChannel.Value = sr.ReadLine(); + } + } + catch (Exception) + { + // file might be in use. + } + + try + { + using (var stream = Storage.GetStream(file_ipc_state_filename)) + using (var sr = new StreamReader(stream)) + { + State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine()); + } + } + catch (Exception) + { + // file might be in use. + } + + try + { + using (var stream = Storage.GetStream(file_ipc_scores_filename)) + using (var sr = new StreamReader(stream)) + { + Score1.Value = int.Parse(sr.ReadLine()); + Score2.Value = int.Parse(sr.ReadLine()); + } + } + catch (Exception) + { + // file might be in use. + } + }, 250, true); } catch (Exception e) { Logger.Error(e, "Stable installation could not be found; disabling file based IPC"); - return; } - const string file_ipc_filename = "ipc.txt"; - const string file_ipc_state_filename = "ipc-state.txt"; - const string file_ipc_scores_filename = "ipc-scores.txt"; - const string file_ipc_channel_filename = "ipc-channel.txt"; - - if (stable.Exists(file_ipc_filename)) - Scheduler.AddDelayed(delegate - { - try - { - using (var stream = stable.GetStream(file_ipc_filename)) - using (var sr = new StreamReader(stream)) - { - var beatmapId = int.Parse(sr.ReadLine()); - var mods = int.Parse(sr.ReadLine()); - - if (lastBeatmapId != beatmapId) - { - lastBeatmapId = beatmapId; - - var existing = ladder.CurrentMatch.Value?.Round.Value?.Beatmaps.FirstOrDefault(b => b.ID == beatmapId && b.BeatmapInfo != null); - - if (existing != null) - Beatmap.Value = existing.BeatmapInfo; - else - { - var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = beatmapId }); - req.Success += b => Beatmap.Value = b.ToBeatmap(Rulesets); - API.Queue(req); - } - } - - Mods.Value = (LegacyMods)mods; - } - } - catch - { - // file might be in use. - } - - try - { - using (var stream = stable.GetStream(file_ipc_channel_filename)) - using (var sr = new StreamReader(stream)) - { - ChatChannel.Value = sr.ReadLine(); - } - } - catch (Exception) - { - // file might be in use. - } - - try - { - using (var stream = stable.GetStream(file_ipc_state_filename)) - using (var sr = new StreamReader(stream)) - { - State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine()); - } - } - catch (Exception) - { - // file might be in use. - } - - try - { - using (var stream = stable.GetStream(file_ipc_scores_filename)) - using (var sr = new StreamReader(stream)) - { - Score1.Value = int.Parse(sr.ReadLine()); - Score2.Value = int.Parse(sr.ReadLine()); - } - } - catch (Exception) - { - // file might be in use. - } - }, 250, true); + return Storage; } /// diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index a5e0e5927a..b75b0056ce 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -1,9 +1,24 @@ // 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.Allocation; +using osu.Framework.Graphics.Sprites; +using osu.Game.Tournament.IPC; + namespace osu.Game.Tournament.Screens { public class SetupScreen : TournamentScreen { + [Resolved] + private MatchIPCInfo ipc { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + AddInternal(new SpriteText + { + Text = (ipc as FileBasedIPC)?.Storage.GetFullPath(string.Empty) + }); + } } } From 96c0c80dc58622af64cba3b020b2434b60132bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Sep 2019 21:20:50 +0200 Subject: [PATCH 076/966] Factor out methods in FilterQueryParser Factor FilterQueryParser.ApplyQueries into shorter methods to reduce method complexity. --- osu.Game/Screens/Select/FilterQueryParser.cs | 102 ++++++++++--------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 3ee704201e..ffe1258168 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -22,54 +22,7 @@ namespace osu.Game.Screens.Select var op = match.Groups["op"].Value; var value = match.Groups["value"].Value; - switch (key) - { - case "stars" when parseFloatWithPoint(value, out var stars): - updateCriteriaRange(ref criteria.StarDifficulty, op, stars, 0.01f / 2); - break; - - case "ar" when parseFloatWithPoint(value, out var ar): - updateCriteriaRange(ref criteria.ApproachRate, op, ar, 0.1f / 2); - break; - - case "dr" when parseFloatWithPoint(value, out var dr): - updateCriteriaRange(ref criteria.DrainRate, op, dr, 0.1f / 2); - break; - - case "cs" when parseFloatWithPoint(value, out var cs): - updateCriteriaRange(ref criteria.CircleSize, op, cs, 0.1f / 2); - break; - - case "bpm" when parseDoubleWithPoint(value, out var bpm): - updateCriteriaRange(ref criteria.BPM, op, bpm, 0.01d / 2); - break; - - case "length" when parseDoubleWithPoint(value.TrimEnd('m', 's', 'h'), out var length): - var scale = - value.EndsWith("ms") ? 1 : - value.EndsWith("s") ? 1000 : - value.EndsWith("m") ? 60000 : - value.EndsWith("h") ? 3600000 : 1000; - - updateCriteriaRange(ref criteria.Length, op, length * scale, scale / 2.0); - break; - - case "divisor" when parseInt(value, out var divisor): - updateCriteriaRange(ref criteria.BeatDivisor, op, divisor); - break; - - case "status" when Enum.TryParse(value, true, out var statusValue): - updateCriteriaRange(ref criteria.OnlineStatus, op, statusValue); - break; - - case "creator": - updateCriteriaText(ref criteria.Creator, op, value); - break; - - case "artist": - updateCriteriaText(ref criteria.Artist, op, value); - break; - } + parseKeywordCriteria(criteria, key, value, op); query = query.Replace(match.ToString(), ""); } @@ -77,6 +30,59 @@ namespace osu.Game.Screens.Select criteria.SearchText = query; } + private static void parseKeywordCriteria(FilterCriteria criteria, string key, string value, string op) + { + switch (key) + { + case "stars" when parseFloatWithPoint(value, out var stars): + updateCriteriaRange(ref criteria.StarDifficulty, op, stars, 0.01f / 2); + break; + + case "ar" when parseFloatWithPoint(value, out var ar): + updateCriteriaRange(ref criteria.ApproachRate, op, ar, 0.1f / 2); + break; + + case "dr" when parseFloatWithPoint(value, out var dr): + updateCriteriaRange(ref criteria.DrainRate, op, dr, 0.1f / 2); + break; + + case "cs" when parseFloatWithPoint(value, out var cs): + updateCriteriaRange(ref criteria.CircleSize, op, cs, 0.1f / 2); + break; + + case "bpm" when parseDoubleWithPoint(value, out var bpm): + updateCriteriaRange(ref criteria.BPM, op, bpm, 0.01d / 2); + break; + + case "length" when parseDoubleWithPoint(value.TrimEnd('m', 's', 'h'), out var length): + var scale = getLengthScale(value); + updateCriteriaRange(ref criteria.Length, op, length * scale, scale / 2.0); + break; + + case "divisor" when parseInt(value, out var divisor): + updateCriteriaRange(ref criteria.BeatDivisor, op, divisor); + break; + + case "status" when Enum.TryParse(value, true, out var statusValue): + updateCriteriaRange(ref criteria.OnlineStatus, op, statusValue); + break; + + case "creator": + updateCriteriaText(ref criteria.Creator, op, value); + break; + + case "artist": + updateCriteriaText(ref criteria.Artist, op, value); + break; + } + } + + private static int getLengthScale(string value) => + value.EndsWith("ms") ? 1 : + value.EndsWith("s") ? 1000 : + value.EndsWith("m") ? 60000 : + value.EndsWith("h") ? 3600000 : 1000; + private static bool parseFloatWithPoint(string value, out float result) => float.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result); From e07aa94fc8701f0a2807ef04cbca20d26f75566c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Sep 2019 04:22:50 +0900 Subject: [PATCH 077/966] Allow reloading ipc source --- osu.Game.Tournament/Screens/SetupScreen.cs | 84 ++++++++++++++++++++-- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index b75b0056ce..992762431e 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -1,9 +1,16 @@ // 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.Graphics.Sprites; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; using osu.Game.Tournament.IPC; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Tournament.Screens { @@ -15,10 +22,79 @@ namespace osu.Game.Tournament.Screens [BackgroundDependencyLoader] private void load() { - AddInternal(new SpriteText + reload(); + } + + private void reload() + { + var fileBasedIpc = ipc as FileBasedIPC; + + InternalChildren = new Drawable[] { - Text = (ipc as FileBasedIPC)?.Storage.GetFullPath(string.Empty) - }); + new ActionableInfo + { + Label = "Current IPC source", + ButtonText = "Refresh", + Action = () => + { + fileBasedIpc?.LocateStableStorage(); + reload(); + }, + Value = fileBasedIpc?.Storage?.GetFullPath(string.Empty) ?? "Not found", + Failing = fileBasedIpc?.Storage == null, + Description = "The osu!stable installation which is currently being used as a data source. If a source is not found, make sure you have created an empty ipc.txt in your stable cutting-edge installation, and that it is registered as the default osu! install." + } + }; + } + + private class ActionableInfo : LabelledComponent + { + private OsuButton button; + + public ActionableInfo() + : base(true) + { + } + + public string ButtonText + { + set => button.Text = value; + } + + public string Value + { + set => valueText.Text = value; + } + + public bool Failing + { + set => valueText.Colour = value ? Color4.Red : Color4.White; + } + + public Action Action; + + private OsuSpriteText valueText; + + protected override Drawable CreateComponent() => new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new Drawable[] + { + valueText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + button = new TriangleButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Size = new Vector2(100, 30), + Action = () => Action?.Invoke() + }, + } + }; } } } From b41ac543c5a4a4d31e783a4c802f80d25871a427 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Sep 2019 04:45:23 +0900 Subject: [PATCH 078/966] Allow changing logged in user --- osu.Game.Tournament/Screens/SetupScreen.cs | 44 ++++++++++++++++++- osu.Game.Tournament/TournamentSceneManager.cs | 1 + .../Sections/General/LoginSettings.cs | 4 +- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 992762431e..8ccb469b13 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -7,6 +7,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Overlays; using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; using osu.Game.Tournament.IPC; using osuTK; @@ -16,12 +18,29 @@ namespace osu.Game.Tournament.Screens { public class SetupScreen : TournamentScreen { + private FillFlowContainer fillFlow; + + private LoginOverlay loginOverlay; + [Resolved] private MatchIPCInfo ipc { get; set; } + [Resolved] + private IAPIProvider api { get; set; } + [BackgroundDependencyLoader] private void load() { + InternalChild = fillFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Padding = new MarginPadding(10), + Spacing = new Vector2(10), + }; + + api.LocalUser.BindValueChanged(_ => Schedule(reload)); reload(); } @@ -29,7 +48,7 @@ namespace osu.Game.Tournament.Screens { var fileBasedIpc = ipc as FileBasedIPC; - InternalChildren = new Drawable[] + fillFlow.Children = new Drawable[] { new ActionableInfo { @@ -43,6 +62,29 @@ namespace osu.Game.Tournament.Screens Value = fileBasedIpc?.Storage?.GetFullPath(string.Empty) ?? "Not found", Failing = fileBasedIpc?.Storage == null, Description = "The osu!stable installation which is currently being used as a data source. If a source is not found, make sure you have created an empty ipc.txt in your stable cutting-edge installation, and that it is registered as the default osu! install." + }, + new ActionableInfo + { + Label = "Current User", + ButtonText = "Change Login", + Action = () => + { + api.Logout(); + + if (loginOverlay == null) + { + AddInternal(loginOverlay = new LoginOverlay() + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }); + } + + loginOverlay.State.Value = Visibility.Visible; + }, + Value = api?.LocalUser.Value.Username, + Failing = api?.IsLoggedIn != true, + Description = "In order to access the API and display metadata, a login is required." } }; } diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs index b1384023d3..58c6e3fee6 100644 --- a/osu.Game.Tournament/TournamentSceneManager.cs +++ b/osu.Game.Tournament/TournamentSceneManager.cs @@ -69,6 +69,7 @@ namespace osu.Game.Tournament RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + new SetupScreen(), new ScheduleScreen(), new LadderScreen(), new LadderEditorScreen(), diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 66fec1ecf9..b02b1a5489 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.General api?.Register(this); } - public void APIStateChanged(IAPIProvider api, APIState state) + public void APIStateChanged(IAPIProvider api, APIState state) => Schedule(() => { form = null; @@ -184,7 +184,7 @@ namespace osu.Game.Overlays.Settings.Sections.General } if (form != null) GetContainingInputManager()?.ChangeFocus(form); - } + }); public override bool AcceptsFocus => true; From 4b7a42119119bbfdb03f7a458572a938714fdd30 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Sep 2019 04:47:51 +0900 Subject: [PATCH 079/966] Set setup screen as default when opening --- osu.Game.Tournament/TournamentSceneManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs index 58c6e3fee6..02ee1c8603 100644 --- a/osu.Game.Tournament/TournamentSceneManager.cs +++ b/osu.Game.Tournament/TournamentSceneManager.cs @@ -130,7 +130,7 @@ namespace osu.Game.Tournament }, }; - SetScreen(typeof(ScheduleScreen)); + SetScreen(typeof(SetupScreen)); } public void SetScreen(Type screenType) From bafb429e9b6ae8ddaf120089f0bf6e845d7c3fc2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Sep 2019 04:49:21 +0900 Subject: [PATCH 080/966] Don't show video background --- osu.Game.Tournament/Screens/SetupScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 8ccb469b13..1cb4917790 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens { - public class SetupScreen : TournamentScreen + public class SetupScreen : TournamentScreen, IProvideVideo { private FillFlowContainer fillFlow; @@ -73,7 +73,7 @@ namespace osu.Game.Tournament.Screens if (loginOverlay == null) { - AddInternal(loginOverlay = new LoginOverlay() + AddInternal(loginOverlay = new LoginOverlay { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, From c92545e294d61ad151aac2197d1bb0882bf8d73d Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 23 Sep 2019 01:41:59 +0200 Subject: [PATCH 081/966] Update osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs Co-Authored-By: Salman Ahmed --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index dc099b14b9..36c8ecf020 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Gameplay /// Sets the input manager child to a new test player loader container instance. /// /// If the test player should behave like the production one. - public void ResetPlayer(bool interactive) + private void resetPlayer(bool interactive) { player = new TestPlayer(interactive, interactive); loader = new TestPlayerLoader(() => player); From e3e245ab20456afd2cf5a4b700a103c73ff9b79f Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 23 Sep 2019 08:15:27 +0300 Subject: [PATCH 082/966] Introduce SessionStatics --- osu.Game/Configuration/SessionStatics.cs | 21 +++++++++++++++++++++ osu.Game/OsuGameBase.cs | 1 + 2 files changed, 22 insertions(+) create mode 100644 osu.Game/Configuration/SessionStatics.cs diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs new file mode 100644 index 0000000000..9afb1bda36 --- /dev/null +++ b/osu.Game/Configuration/SessionStatics.cs @@ -0,0 +1,21 @@ +// 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.Configuration; + +namespace osu.Game.Configuration +{ + public class SessionStatics : ConfigManager + { + // This is an in-memory store. + protected override void PerformLoad() + { + } + + protected override bool PerformSave() => true; + } + + public enum Statics + { + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index d6b8ad3e67..b79de0aa94 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -189,6 +189,7 @@ namespace osu.Game dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore)); + dependencies.Cache(new SessionStatics()); dependencies.Cache(new OsuColour()); fileImporters.Add(BeatmapManager); From 5024770544999feda8849f7463102b1db5fe2283 Mon Sep 17 00:00:00 2001 From: LeNitrous Date: Mon, 23 Sep 2019 20:52:44 +0800 Subject: [PATCH 083/966] move common logic to IntroScreen --- osu.Game/Screens/Menu/IntroCircles.cs | 74 ++++++----------------- osu.Game/Screens/Menu/IntroScreen.cs | 80 +++++++++++++++++++++++-- osu.Game/Screens/Menu/IntroTriangles.cs | 65 ++++---------------- 3 files changed, 104 insertions(+), 115 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index c069f82134..d5d7f5cb7a 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -2,86 +2,46 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio.Sample; -using osu.Framework.Audio.Track; -using osu.Framework.Bindables; +using osu.Framework.Audio; using osu.Framework.Screens; using osu.Framework.Graphics; -using osu.Framework.MathUtils; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.IO.Archives; namespace osu.Game.Screens.Menu { public class IntroCircles : IntroScreen { - private const string menu_music_beatmap_hash = "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83"; + protected override string BeatmapHash => "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83"; - private SampleChannel welcome; - - private Bindable menuMusic; - - private Track track; - - private WorkingBeatmap introBeatmap; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game, ISampleStore samples) - { - menuMusic = config.GetBindable(OsuSetting.MenuMusic); - - BeatmapSetInfo setInfo = null; - - if (!menuMusic.Value) - { - var sets = beatmaps.GetAllUsableBeatmapSets(); - if (sets.Count > 0) - setInfo = beatmaps.QueryBeatmapSet(s => s.ID == sets[RNG.Next(0, sets.Count - 1)].ID); - } - - if (setInfo == null) - { - setInfo = beatmaps.QueryBeatmapSet(b => b.Hash == menu_music_beatmap_hash); - - if (setInfo == null) - { - // we need to import the default menu background beatmap - setInfo = beatmaps.Import(new ZipArchiveReader(game.Resources.GetStream(@"Tracks/circles.osz"), "circles.osz")).Result; - - setInfo.Protected = true; - beatmaps.Update(setInfo); - } - } - - introBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); - track = introBeatmap.Track; - - if (config.Get(OsuSetting.MenuVoice)) - welcome = samples.Get(@"welcome"); - } + protected override string BeatmapFile => "circles.osz"; private const double delay_step_one = 2300; private const double delay_step_two = 600; + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + if (MenuVoice.Value) + SetWelcome(); + } + protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); if (!resuming) { - Beatmap.Value = introBeatmap; - introBeatmap = null; + Beatmap.Value = IntroBeatmap; + IntroBeatmap = null; - welcome?.Play(); + Welcome?.Play(); Scheduler.AddDelayed(delegate { // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. - if (menuMusic.Value) + if (MenuMusic.Value) { - track.Restart(); - track = null; + Track.Restart(); + Track = null; } PrepareMenuLoad(); @@ -97,7 +57,7 @@ namespace osu.Game.Screens.Menu public override void OnSuspending(IScreen next) { - track = null; + Track = null; this.FadeOut(300); base.OnSuspending(next); diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 4d0f7ff87a..651fa7583d 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -4,12 +4,19 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.MathUtils; using osu.Framework.Screens; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.IO.Archives; using osu.Game.Screens.Backgrounds; +using osu.Game.Skinning; +using osu.Game.Online.API; +using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -17,6 +24,10 @@ namespace osu.Game.Screens.Menu { public abstract class IntroScreen : StartupScreen { + protected abstract string BeatmapHash { get; } + + protected abstract string BeatmapFile { get; } + private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); public const int EXIT_DELAY = 3000; @@ -24,24 +35,83 @@ namespace osu.Game.Screens.Menu [Resolved] private AudioManager audio { get; set; } + protected SampleChannel Welcome; + private SampleChannel seeya; - private Bindable menuVoice; + protected Bindable MenuVoice; + + protected Bindable MenuMusic; + + protected Track Track; + + protected WorkingBeatmap IntroBeatmap; private LeasedBindable beatmap; public new Bindable Beatmap => beatmap; + protected Bindable User; + + protected Bindable Skin; + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); [BackgroundDependencyLoader] - private void load(OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) + private void load(OsuConfigManager config, IAPIProvider api, SkinManager skinManager, BeatmapManager beatmaps, Framework.Game game) { // prevent user from changing beatmap while the intro is still runnning. beatmap = base.Beatmap.BeginLease(false); - menuVoice = config.GetBindable(OsuSetting.MenuVoice); - seeya = audio.Samples.Get(@"seeya"); + MenuVoice = config.GetBindable(OsuSetting.MenuVoice); + MenuMusic = config.GetBindable(OsuSetting.MenuMusic); + + User = api.LocalUser.GetBoundCopy(); + Skin = skinManager.CurrentSkin.GetBoundCopy(); + + Skin.BindValueChanged(_ => updateSeeya(), true); + + BeatmapSetInfo setInfo = null; + + if (!MenuMusic.Value) + { + var sets = beatmaps.GetAllUsableBeatmapSets(); + if (sets.Count > 0) + setInfo = beatmaps.QueryBeatmapSet(s => s.ID == sets[RNG.Next(0, sets.Count - 1)].ID); + } + + if (setInfo == null) + { + setInfo = beatmaps.QueryBeatmapSet(b => b.Hash == BeatmapHash); + + if (setInfo == null) + { + // we need to import the default menu background beatmap + setInfo = beatmaps.Import(new ZipArchiveReader(game.Resources.GetStream($"Tracks/{BeatmapFile}"), BeatmapFile)).Result; + + setInfo.Protected = true; + beatmaps.Update(setInfo); + } + } + + IntroBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); + Track = IntroBeatmap.Track; + } + + private void updateSeeya() + { + if (User.Value?.IsSupporter ?? false) + seeya = Skin.Value.GetSample(new SampleInfo("seeya")) ?? audio.Samples.Get(@"seeya"); + else + seeya = audio.Samples.Get(@"seeya"); + } + + protected void SetWelcome() + { + if (User.Value?.IsSupporter ?? false) + Welcome = Skin.Value.GetSample(new SampleInfo("welcome")) ?? audio.Samples.Get(@"welcome"); + else + Welcome = audio.Samples.Get(@"welcome"); } /// @@ -61,7 +131,7 @@ namespace osu.Game.Screens.Menu double fadeOutTime = EXIT_DELAY; //we also handle the exit transition. - if (menuVoice.Value) + if (MenuVoice.Value) seeya.Play(); else fadeOutTime = 500; diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index db970dd76e..77700900a8 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -6,9 +6,6 @@ using System.Collections.Generic; using System.IO; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Audio.Track; -using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -17,12 +14,9 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Video; using osu.Framework.MathUtils; using osu.Framework.Timing; -using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.IO.Archives; using osu.Game.Rulesets; using osu.Game.Screens.Backgrounds; using osuTK; @@ -32,9 +26,9 @@ namespace osu.Game.Screens.Menu { public class IntroTriangles : IntroScreen { - private const string menu_music_beatmap_hash = "a1556d0801b3a6b175dda32ef546f0ec812b400499f575c44fccbe9c67f9b1e5"; + protected override string BeatmapHash => "a1556d0801b3a6b175dda32ef546f0ec812b400499f575c44fccbe9c67f9b1e5"; - private SampleChannel welcome; + protected override string BeatmapFile => "triangles.osz"; protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false) { @@ -44,48 +38,13 @@ namespace osu.Game.Screens.Menu [Resolved] private AudioManager audio { get; set; } - private Bindable menuMusic; - private Track track; - private WorkingBeatmap introBeatmap; - private BackgroundScreenDefault background; [BackgroundDependencyLoader] - private void load(OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) + private void load(AudioManager audio) { - menuMusic = config.GetBindable(OsuSetting.MenuMusic); - - BeatmapSetInfo setInfo = null; - - if (!menuMusic.Value) - { - var sets = beatmaps.GetAllUsableBeatmapSets(); - if (sets.Count > 0) - setInfo = beatmaps.QueryBeatmapSet(s => s.ID == sets[RNG.Next(0, sets.Count - 1)].ID); - } - - if (setInfo == null) - { - setInfo = beatmaps.QueryBeatmapSet(b => b.Hash == menu_music_beatmap_hash); - - if (setInfo == null) - { - // we need to import the default menu background beatmap - setInfo = beatmaps.Import(new ZipArchiveReader(game.Resources.GetStream(@"Tracks/triangles.osz"), "triangles.osz")).Result; - - setInfo.Protected = true; - beatmaps.Update(setInfo); - } - } - - introBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); - - track = introBeatmap.Track; - track.Reset(); - - if (config.Get(OsuSetting.MenuVoice) && !menuMusic.Value) - // triangles has welcome sound included in the track. only play this if the user doesn't want menu music. - welcome = audio.Samples.Get(@"welcome"); + if (MenuVoice.Value && !MenuMusic.Value) + SetWelcome(); } protected override void LogoArriving(OsuLogo logo, bool resuming) @@ -96,24 +55,24 @@ namespace osu.Game.Screens.Menu if (!resuming) { - Beatmap.Value = introBeatmap; - introBeatmap = null; + Beatmap.Value = IntroBeatmap; + IntroBeatmap = null; PrepareMenuLoad(); LoadComponentAsync(new TrianglesIntroSequence(logo, background) { RelativeSizeAxes = Axes.Both, - Clock = new FramedClock(menuMusic.Value ? track : null), + Clock = new FramedClock(MenuMusic.Value ? Track : null), LoadMenu = LoadMenu }, t => { AddInternal(t); - welcome?.Play(); + Welcome?.Play(); // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. - if (menuMusic.Value) - track.Start(); + if (MenuMusic.Value) + Track.Start(); }); } } @@ -126,7 +85,7 @@ namespace osu.Game.Screens.Menu public override void OnSuspending(IScreen next) { - track = null; + Track = null; base.OnSuspending(next); } From ffbab2535856f37dacdb6f49f494aa1ed20f3ccf Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 23 Sep 2019 16:12:43 +0300 Subject: [PATCH 084/966] Fix incorrect icon margin in ChangelogOverlay --- osu.Game/Overlays/Changelog/ChangelogBuild.cs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index 11dc2049fd..05bf56bc33 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -15,6 +15,7 @@ using osu.Game.Users; using osuTK.Graphics; using osu.Framework.Allocation; using System.Net; +using osuTK; namespace osu.Game.Overlays.Changelog { @@ -67,21 +68,31 @@ namespace osu.Game.Overlays.Changelog foreach (APIChangelogEntry entry in categoryEntries) { - LinkFlowContainer title = new LinkFlowContainer + LinkFlowContainer title; + + Container titleContainer = new Container { - Direction = FillDirection.Full, - RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, Margin = new MarginPadding { Vertical = 5 }, + Child = title = new LinkFlowContainer + { + Direction = FillDirection.Full, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } }; var entryColour = entry.Major ? colours.YellowLight : Color4.White; - title.AddIcon(entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus, t => + titleContainer.Add(new SpriteIcon { - t.Font = fontSmall; - t.Colour = entryColour; - t.Padding = new MarginPadding { Left = -17, Right = 5 }; + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Size = new Vector2(fontSmall.Size), + Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus, + Colour = entryColour, + Margin = new MarginPadding { Right = 5 }, }); title.AddText(entry.Title, t => @@ -139,7 +150,7 @@ namespace osu.Game.Overlays.Changelog t.Colour = entryColour; }); - ChangelogEntries.Add(title); + ChangelogEntries.Add(titleContainer); if (!string.IsNullOrEmpty(entry.MessageHtml)) { From 5c4dfe0809c6865adf8f8daec0756935200f1ee0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 23 Sep 2019 17:05:19 +0300 Subject: [PATCH 085/966] Apply suggested change --- osu.Game/Overlays/Changelog/ChangelogBuild.cs | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index 05bf56bc33..bce1be5941 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -68,6 +68,8 @@ namespace osu.Game.Overlays.Changelog foreach (APIChangelogEntry entry in categoryEntries) { + var entryColour = entry.Major ? colours.YellowLight : Color4.White; + LinkFlowContainer title; Container titleContainer = new Container @@ -75,26 +77,26 @@ namespace osu.Game.Overlays.Changelog AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Margin = new MarginPadding { Vertical = 5 }, - Child = title = new LinkFlowContainer + Children = new Drawable[] { - Direction = FillDirection.Full, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Size = new Vector2(fontSmall.Size), + Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus, + Colour = entryColour, + Margin = new MarginPadding { Right = 5 }, + }, + title = new LinkFlowContainer + { + Direction = FillDirection.Full, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } } }; - var entryColour = entry.Major ? colours.YellowLight : Color4.White; - - titleContainer.Add(new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreRight, - Size = new Vector2(fontSmall.Size), - Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus, - Colour = entryColour, - Margin = new MarginPadding { Right = 5 }, - }); - title.AddText(entry.Title, t => { t.Font = fontLarge; From 8df77ffe924a36c750cc1a3d30216e038b57d06c Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 23 Sep 2019 16:48:30 +0200 Subject: [PATCH 086/966] Revert test scene changes --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 90 ++----------------- 1 file changed, 7 insertions(+), 83 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index dc099b14b9..ab519360ac 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -3,20 +3,14 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; using osu.Framework.Screens; -using osu.Game.Graphics.Containers; -using osu.Game.Overlays; -using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; @@ -30,35 +24,19 @@ namespace osu.Game.Tests.Visual.Gameplay public class TestScenePlayerLoader : ManualInputManagerTestScene { private TestPlayerLoader loader; - private TestPlayerLoaderContainer container; - private TestPlayer player; - - [Resolved] - private AudioManager audioManager { get; set; } + private OsuScreenStack stack; [SetUp] public void Setup() => Schedule(() => { - ResetPlayer(false); + InputManager.Child = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); }); - /// - /// Sets the input manager child to a new test player loader container instance. - /// - /// If the test player should behave like the production one. - public void ResetPlayer(bool interactive) - { - player = new TestPlayer(interactive, interactive); - loader = new TestPlayerLoader(() => player); - container = new TestPlayerLoaderContainer(loader); - InputManager.Child = container; - } - [Test] public void TestBlockLoadViaMouseMovement() { - AddStep("load dummy beatmap", () => ResetPlayer(false)); + AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false)))); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20); AddAssert("loader still active", () => loader.IsCurrentScreen()); @@ -71,13 +49,13 @@ namespace osu.Game.Tests.Visual.Gameplay Player player = null; SlowLoadPlayer slowPlayer = null; - AddStep("load dummy beatmap", () => ResetPlayer(false)); + AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer(false, false)))); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); AddUntilStep("wait for player to be current", () => player.IsCurrentScreen()); AddStep("load slow dummy beatmap", () => { - InputManager.Children = container = new TestPlayerLoaderContainer(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + stack.Push(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000); }); @@ -87,6 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestModReinstantiation() { + TestPlayer player = null; TestMod gameMod = null; TestMod playerMod1 = null; TestMod playerMod2 = null; @@ -94,7 +73,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("load player", () => { Mods.Value = new[] { gameMod = new TestMod() }; - ResetPlayer(true); + stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer())); }); AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen()); @@ -118,61 +97,6 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("player mods applied", () => playerMod2.Applied); } - [Test] - public void TestMutedNotification() - { - AddStep("set master volume to 0%", () => audioManager.Volume.Value = 0); - AddStep("reset notification lock", () => PlayerLoader.ResetNotificationLock()); - //AddStep("reset notification overlay", () => notificationOverlay); - AddStep("load player", () => ResetPlayer(false)); - AddUntilStep("wait for player", () => player.IsLoaded); - - AddAssert("check for notification", () => container.NotificationOverlay.UnreadCount.Value == 1); - AddAssert("click notification", () => - { - var scrollContainer = container.NotificationOverlay.Children.Last() as OsuScrollContainer; - var flowContainer = scrollContainer.Children.First() as FillFlowContainer; - return flowContainer.Children.First().First().Click(); - }); - AddAssert("check master volume", () => audioManager.Volume.IsDefault); - - AddStep("restart player", () => - { - var lastPlayer = player; - player = null; - lastPlayer.Restart(); - }); - } - - private class TestPlayerLoaderContainer : Container - { - private TestPlayerLoader loader; - - [Cached] - public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }; - - [Cached] - public VolumeOverlay VolumeOverlay { get; } = new VolumeOverlay - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - }; - - public TestPlayerLoaderContainer(TestPlayerLoader testPlayerLoader) - { - Children = new Drawable[] - { - loader = testPlayerLoader, - NotificationOverlay, - VolumeOverlay - }; - } - } - private class TestPlayerLoader : PlayerLoader { public new VisualSettings VisualSettings => base.VisualSettings; From 53603b559176e4ddbc62e5e3e9d54f67785b2d62 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2019 20:15:51 +0000 Subject: [PATCH 087/966] Bump System.ComponentModel.Annotations from 4.5.0 to 4.6.0 Bumps [System.ComponentModel.Annotations](https://github.com/dotnet/corefx) from 4.5.0 to 4.6.0. - [Release notes](https://github.com/dotnet/corefx/releases) - [Commits](https://github.com/dotnet/corefx/commits) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a27a94b8f9..a699217503 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -30,6 +30,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index a6516e6d1b..7803ea1e49 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -123,7 +123,7 @@ - + From 78ce62b187798d8e194c0c89ea6ee3a29154bc3b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2019 20:29:36 +0000 Subject: [PATCH 088/966] Bump System.IO.Packaging from 4.5.0 to 4.6.0 Bumps [System.IO.Packaging](https://github.com/dotnet/corefx) from 4.5.0 to 4.6.0. - [Release notes](https://github.com/dotnet/corefx/releases) - [Commits](https://github.com/dotnet/corefx/commits) Signed-off-by: dependabot-preview[bot] --- osu.Desktop/osu.Desktop.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 538aaf2d7a..03b002add7 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -26,7 +26,7 @@ - + From 50dcb70342c22f97398e9c45b2f7c8576f52807d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2019 21:04:20 +0000 Subject: [PATCH 089/966] Bump Microsoft.Win32.Registry from 4.5.0 to 4.6.0 Bumps [Microsoft.Win32.Registry](https://github.com/dotnet/corefx) from 4.5.0 to 4.6.0. - [Release notes](https://github.com/dotnet/corefx/releases) - [Commits](https://github.com/dotnet/corefx/commits) Signed-off-by: dependabot-preview[bot] --- osu.Desktop/osu.Desktop.csproj | 2 +- osu.Game.Tournament/osu.Game.Tournament.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 538aaf2d7a..9e8bb431c0 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.Game.Tournament/osu.Game.Tournament.csproj b/osu.Game.Tournament/osu.Game.Tournament.csproj index 4790fcbcde..bddaff0a80 100644 --- a/osu.Game.Tournament/osu.Game.Tournament.csproj +++ b/osu.Game.Tournament/osu.Game.Tournament.csproj @@ -11,6 +11,6 @@ - + \ No newline at end of file From ec78889e94178357e1d18303ca0f7164f5e31955 Mon Sep 17 00:00:00 2001 From: LeNitrous Date: Tue, 24 Sep 2019 08:14:20 +0800 Subject: [PATCH 090/966] remove unused dependencies --- osu.Game/Screens/Menu/IntroCircles.cs | 3 +-- osu.Game/Screens/Menu/IntroTriangles.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index d5d7f5cb7a..a861d54663 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Screens; using osu.Framework.Graphics; @@ -18,7 +17,7 @@ namespace osu.Game.Screens.Menu private const double delay_step_two = 600; [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { if (MenuVoice.Value) SetWelcome(); diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 77700900a8..5b49a81a5a 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Menu private BackgroundScreenDefault background; [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { if (MenuVoice.Value && !MenuMusic.Value) SetWelcome(); From 143d7ab640b588569e5dc31bd0d87f79b8a78401 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 24 Sep 2019 04:53:26 +0300 Subject: [PATCH 091/966] Add test scene for spinner rotation --- .../TestSceneSpinnerRotation.cs | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs new file mode 100644 index 0000000000..e9fa8e46ed --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -0,0 +1,104 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Logging; +using osu.Framework.MathUtils; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Screens.Play; +using osu.Game.Tests.Visual; +using osuTK; +using System.Collections.Generic; +using System.Linq; +using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneSpinnerRotation : TestSceneOsuPlayer + { + [Resolved] + private AudioManager audioManager { get; set; } + + private TrackVirtualManual track; + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) + { + var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + track = (TrackVirtualManual)working.Track; + return working; + } + + private DrawableSpinner drawableSpinner; + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.First()); + + // wait for frame stable clock time to hit 0 (for some reason, executing a seek while current time is below 0 doesn't seek successfully) + addSeekStep(0); + } + + [Test] + public void TestSpinnerRewindingRotation() + { + addSeekStep(5000); + AddAssert("is rotation absolute not almost 0", () => !Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, 0, 100)); + + addSeekStep(0); + AddAssert("is rotation absolute almost 0", () => Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, 0, 100)); + } + + [Test] + public void TestSpinnerMiddleRewindingRotation() + { + double estimatedRotation = 0; + + addSeekStep(5000); + AddStep("retrieve rotation", () => estimatedRotation = drawableSpinner.Disc.RotationAbsolute); + + addSeekStep(2500); + addSeekStep(5000); + AddAssert("is rotation absolute almost same", () => Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, estimatedRotation, 100)); + } + + private void addSeekStep(double time) + { + AddStep($"seek to {time}", () => track.Seek(time)); + + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, ((TestPlayer)Player).DrawableRuleset.FrameStableClock.CurrentTime, 100)); + } + + protected override Player CreatePlayer(Ruleset ruleset) + { + Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray(); + return new TestPlayer(); + } + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap + { + HitObjects = new List + { + new Spinner + { + Position = new Vector2(256, 192), + EndTime = 5000, + }, + // placeholder object to avoid hitting the results screen + new HitObject + { + StartTime = 99999, + } + } + }; + } +} From ba679684be0aab707d545b111973253d5926f647 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 24 Sep 2019 04:59:57 +0300 Subject: [PATCH 092/966] Trim whitespaces --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index e9fa8e46ed..4b98e84866 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Tests Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray(); return new TestPlayer(); } - + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap { HitObjects = new List From 18fd7aa8055a406ceecd242a359a2ec6072dee10 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 24 Sep 2019 05:10:06 +0300 Subject: [PATCH 093/966] Remove redundant using directive --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index 4b98e84866..7e792f0b40 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -4,7 +4,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Logging; using osu.Framework.MathUtils; using osu.Framework.Testing; using osu.Framework.Timing; From 267e12ce3c0d88cab712d562a1c3f27dd6321fe3 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 24 Sep 2019 05:45:47 +0300 Subject: [PATCH 094/966] Add sample usage to the session statics --- osu.Game/Configuration/SessionStatics.cs | 1 + osu.Game/Screens/Menu/MainMenu.cs | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 9afb1bda36..0c1ea1e568 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -17,5 +17,6 @@ namespace osu.Game.Configuration public enum Statics { + LoginOverlayDisplayed, } } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index dd81569e26..1834221d35 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -52,6 +52,9 @@ namespace osu.Game.Screens.Menu [Resolved(canBeNull: true)] private LoginOverlay login { get; set; } + [Resolved] + private SessionStatics statics { get; set; } + [Resolved] private IAPIProvider api { get; set; } @@ -170,7 +173,6 @@ namespace osu.Game.Screens.Menu Beatmap.ValueChanged += beatmap_ValueChanged; } - private bool loginDisplayed; private bool exitConfirmed; protected override void LogoArriving(OsuLogo logo, bool resuming) @@ -198,10 +200,12 @@ namespace osu.Game.Screens.Menu bool displayLogin() { - if (!loginDisplayed) + var loginDisplayed = statics.GetBindable(Statics.LoginOverlayDisplayed); + + if (!loginDisplayed.Value) { Scheduler.AddDelayed(() => login?.Show(), 500); - loginDisplayed = true; + loginDisplayed.Value = true; } return true; From 4555ecc5e05d4c053e8a7822ca736c4328481e75 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Sep 2019 15:09:08 +0900 Subject: [PATCH 095/966] Check for exact key --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 7ac6b5c696..ed8e4c70f9 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -185,7 +185,7 @@ namespace osu.Game.Screens.Menu { if (State == ButtonSystemState.Initial) { - if (buttonsTopLevel.Any(b => e.PressedKeys.Contains(b.TriggerKey))) + if (buttonsTopLevel.Any(b => e.Key == b.TriggerKey)) { logo?.Click(); return true; From 6e619fbd71ad8b5654e60ed7850b05ee0865f1a1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2019 06:35:04 +0000 Subject: [PATCH 096/966] Bump ppy.osu.Framework from 2019.921.0 to 2019.924.0 Bumps [ppy.osu.Framework](https://github.com/ppy/osu-framework) from 2019.921.0 to 2019.924.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.921.0...2019.924.0) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a699217503..83632f3d41 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 7803ea1e49..29a12f3707 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,7 +118,7 @@ - + From 50efb4414f87a78b3fda6595056b6851389740f7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2019 06:35:31 +0000 Subject: [PATCH 097/966] Bump ppy.osu.Framework.Android from 2019.921.0 to 2019.924.0 Bumps [ppy.osu.Framework.Android](https://github.com/ppy/osu-framework) from 2019.921.0 to 2019.924.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.921.0...2019.924.0) Signed-off-by: dependabot-preview[bot] --- osu.Android.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android.props b/osu.Android.props index c57fc342ba..46fd5424df 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -62,6 +62,6 @@ - + From 60c9519095313948a05c27ca04aece93a9f2d7fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 16:21:37 +0900 Subject: [PATCH 098/966] Add proper signing and github release support --- fastlane/Fastfile | 48 +++++++++++++++++++++++++++++++++++++++++----- fastlane/README.md | 5 +++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 906d284bc9..7adf42a1eb 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -4,14 +4,12 @@ platform :android do desc 'Deploy to play store' lane :beta do |options| - # update csproj version update_version( - solution_path: 'osu.Android.sln', version: options[:version], build: options[:build], ) - build() + build(options) supply( apk: './osu.Android/bin/Release/sh.ppy.osulazer-Signed.apk', @@ -21,8 +19,35 @@ desc 'Deploy to play store' ) end + desc 'Deploy to github release' + lane :build_github do |options| + + update_version( + version: options[:version], + build: options[:build], + ) + + build(options) + + client = HTTPClient.new + changelog = client.get_content 'https://gist.githubusercontent.com/peppy/aaa2ec1a323554b619671cac6dbbb776/raw' + changelog.gsub!('$BUILD_ID', options[:build]) + + set_github_release( + repository_name: "ppy/osu", + api_token: ENV["GITHUB_TOKEN"], + name: options[:build], + tag_name: options[:build], + is_draft: true, + description: changelog, + commitish: "master", + upload_assets: ["osu.Android/bin/Release/sh.ppy.osulazer.apk"] + ) + + end + desc 'Compile the project' - lane :build do + lane :build do |options| nuget_restore( project_path: 'osu.Android.sln' ) @@ -31,11 +56,24 @@ desc 'Deploy to play store' build_configuration: 'Release', solution_path: 'osu.Android.sln', platform: "android", + output_path: "osu.Android/bin/Release/", + keystore_path: options[:keystore_path], + keystore_alias: options[:keystore_alias], + keystore_password: ENV["KEYSTORE_PASSWORD"] ) end lane :update_version do |options| - app_version(options) + + split = options[:build].split('.') + split[1] = split[1].to_s.rjust(4, '0') + android_build = split.join('') + + app_version( + solution_path: 'osu.Android.sln', + version: options[:version], + build: android_build, + ) end end diff --git a/fastlane/README.md b/fastlane/README.md index 6145620870..a400ed9516 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -21,6 +21,11 @@ or alternatively using `brew cask install fastlane` fastlane android beta ``` Deploy to play store +### android build_github +``` +fastlane android build_github +``` +Deploy to github release ### android build ``` fastlane android build From 1860c2f9cea07e13cbf8c81c4d23ba45f2732266 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 16:22:30 +0900 Subject: [PATCH 099/966] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index c57fc342ba..46fd5424df 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -62,6 +62,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a699217503..83632f3d41 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 7803ea1e49..30f1da362d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,8 +118,8 @@ - - + + From d08fc563707f1bfe010bc889cbb51ae824583da0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 16:33:48 +0900 Subject: [PATCH 100/966] Add apk download link in README --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 56491a4be4..aefeb2e96e 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,10 @@ If you are not interested in developing the game, you can still consume our [bin **Latest build:** -| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | -| ------------- | ------------- | +| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [iOS(iOS 10+)](https://testflight.apple.com/join/2tLcjWlF) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) +| ------------- | ------------- | ------------- | ------------- | - **Linux** users are recommended to self-compile until we have official deployment in place. -- **iOS** users can join the [TestFlight beta program](https://testflight.apple.com/join/2tLcjWlF) (note that due to high demand this is regularly full). -- **Android** users can self-compile, and expect a public beta soon. If your platform is not listed above, there is still a chance you can manually build it by following the instructions below. From 315dcc81583ad8da74fb0ded9e8d64b7b5f22b4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 16:42:05 +0900 Subject: [PATCH 101/966] Update fastlane --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index ac46fddb41..7df9c46482 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,7 +5,7 @@ GEM addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) atomos (0.1.3) - babosa (1.0.2) + babosa (1.0.3) claide (1.0.3) colored (1.2) colored2 (3.1.2) From 75cceb9e303568ab94b2ce416ac4791044010ac4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Sep 2019 16:47:34 +0900 Subject: [PATCH 102/966] Fix LifetimeChanged being invoked before lifetime is set --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index b94de0df89..8d8f8a419f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -316,8 +316,8 @@ namespace osu.Game.Rulesets.Objects.Drawables get => lifetimeStart ?? (HitObject.StartTime - InitialLifetimeOffset); set { - base.LifetimeStart = value; lifetimeStart = value; + base.LifetimeStart = value; } } From af0c15a93c171c3559b6fafb344ac3376b7eb986 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Sep 2019 16:48:39 +0900 Subject: [PATCH 103/966] Fix initial hitobject states not being recomputed correctly --- osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index bd1f496dfa..e00597dd56 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -77,6 +77,9 @@ namespace osu.Game.Rulesets.UI.Scrolling if (!initialStateCache.IsValid) { + foreach (var cached in hitObjectInitialStateCache.Values) + cached.Invalidate(); + switch (direction.Value) { case ScrollingDirection.Up: From 4abe0473b9093c8d6dd4f9d6e28364c7e34e3f89 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Sep 2019 16:49:42 +0900 Subject: [PATCH 104/966] Fix relative beat length not considering slider multiplier --- .../TestSceneDrawableScrollingRuleset.cs | 16 ++++++++++++++++ .../UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index 60ace8ea69..86f7896457 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -115,6 +116,19 @@ namespace osu.Game.Tests.Visual.Gameplay assertPosition(4, 1f); } + [Test] + public void TestSliderMultiplierDoesnotAffectRelativeBeatLength() + { + var beatmap = createBeatmap(new TimingControlPoint { BeatLength = time_range }); + beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2; + + createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true); + AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 5000); + + for (int i = 0; i < 5; i++) + assertPosition(i, i / 5f); + } + private void assertPosition(int index, float relativeY) => AddAssert($"hitobject {index} at {relativeY}", () => Precision.AlmostEquals(drawableRuleset.Playfield.AllHitObjects.ElementAt(index).DrawPosition.Y, drawableRuleset.Playfield.HitObjectContainer.DrawHeight * relativeY)); @@ -193,6 +207,8 @@ namespace osu.Game.Tests.Visual.Gameplay protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping; + public new Bindable TimeRange => base.TimeRange; + public TestDrawableScrollingRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 64e491858b..3d56543bab 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.UI.Scrolling if (duration > maxDuration) { maxDuration = duration; - baseBeatLength = timingPoints[i].BeatLength; + baseBeatLength = timingPoints[i].BeatLength / Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier; } } } From c6fe8587e3c6c023db6fe81f77a75ee4de33a612 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 17:45:45 +0900 Subject: [PATCH 105/966] Read build from VersionCode --- osu.Android/OsuGameAndroid.cs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs index d9bdd9c0c2..aca36b59aa 100644 --- a/osu.Android/OsuGameAndroid.cs +++ b/osu.Android/OsuGameAndroid.cs @@ -9,6 +9,23 @@ namespace osu.Android { public class OsuGameAndroid : OsuGame { - public override Version AssemblyVersion => new Version(Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0).VersionName); + public override Version AssemblyVersion + { + get + { + string versionName = Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0).VersionCode.ToString(); + + try + { + // undo play store version garbling + return new Version(int.Parse(versionName.Substring(0, 4)), int.Parse(versionName.Substring(4, 4)), int.Parse(versionName.Substring(8, 1))); + } + catch + { + } + + return new Version(versionName); + } + } } -} +} \ No newline at end of file From 1c474de0ed8cd3a9cf778340bba142efcf4780e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 18:03:01 +0900 Subject: [PATCH 106/966] Move post-update notification logic to UpdateManager base class --- osu.Desktop/OsuGameDesktop.cs | 1 + osu.Desktop/Overlays/VersionManager.cs | 55 +-------------- osu.Desktop/Updater/SquirrelUpdateManager.cs | 2 +- .../Updater/SimpleUpdateManager.cs | 18 +++-- osu.Game/Updater/UpdateManager.cs | 67 +++++++++++++++++++ 5 files changed, 78 insertions(+), 65 deletions(-) rename {osu.Desktop => osu.Game}/Updater/SimpleUpdateManager.cs (87%) create mode 100644 osu.Game/Updater/UpdateManager.cs diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 761f52f961..7725ee6451 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -17,6 +17,7 @@ using osu.Framework.Logging; using osu.Framework.Platform.Windows; using osu.Framework.Screens; using osu.Game.Screens.Menu; +using osu.Game.Updater; namespace osu.Desktop { diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 51e801c185..6eed46867a 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -8,11 +8,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays; -using osu.Game.Overlays.Notifications; using osuTK; using osuTK.Graphics; @@ -20,17 +17,9 @@ namespace osu.Desktop.Overlays { public class VersionManager : OverlayContainer { - private OsuConfigManager config; - private OsuGameBase game; - private NotificationOverlay notificationOverlay; - [BackgroundDependencyLoader] - private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config) + private void load(OsuColour colours, TextureStore textures, OsuGameBase game) { - notificationOverlay = notification; - this.config = config; - this.game = game; - AutoSizeAxes = Axes.Both; Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; @@ -85,48 +74,6 @@ namespace osu.Desktop.Overlays }; } - protected override void LoadComplete() - { - base.LoadComplete(); - - var version = game.Version; - var lastVersion = config.Get(OsuSetting.Version); - - if (game.IsDeployedBuild && version != lastVersion) - { - config.Set(OsuSetting.Version, version); - - // only show a notification if we've previously saved a version to the config file (ie. not the first run). - if (!string.IsNullOrEmpty(lastVersion)) - notificationOverlay.Post(new UpdateCompleteNotification(version)); - } - } - - private class UpdateCompleteNotification : SimpleNotification - { - private readonly string version; - - public UpdateCompleteNotification(string version) - { - this.version = version; - Text = $"You are now running osu!lazer {version}.\nClick to see what's new!"; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay) - { - Icon = FontAwesome.Solid.CheckSquare; - IconBackgound.Colour = colours.BlueDark; - - Activated = delegate - { - notificationOverlay.Hide(); - changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version); - return true; - }; - } - } - protected override void PopIn() { this.FadeIn(1400, Easing.OutQuint); diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index fa41c061b5..60b47a8b3a 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -20,7 +20,7 @@ using LogLevel = Splat.LogLevel; namespace osu.Desktop.Updater { - public class SquirrelUpdateManager : Component + public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager { private UpdateManager updateManager; private NotificationOverlay notificationOverlay; diff --git a/osu.Desktop/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs similarity index 87% rename from osu.Desktop/Updater/SimpleUpdateManager.cs rename to osu.Game/Updater/SimpleUpdateManager.cs index 5184791de1..eec27d3325 100644 --- a/osu.Desktop/Updater/SimpleUpdateManager.cs +++ b/osu.Game/Updater/SimpleUpdateManager.cs @@ -6,31 +6,25 @@ using System.Threading.Tasks; using Newtonsoft.Json; using osu.Framework; using osu.Framework.Allocation; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.IO.Network; using osu.Framework.Platform; -using osu.Game; -using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -namespace osu.Desktop.Updater +namespace osu.Game.Updater { /// /// An update manager that shows notifications if a newer release is detected. /// Installation is left up to the user. /// - internal class SimpleUpdateManager : CompositeDrawable + public class SimpleUpdateManager : UpdateManager { - private NotificationOverlay notificationOverlay; private string version; private GameHost host; [BackgroundDependencyLoader] - private void load(NotificationOverlay notification, OsuGameBase game, GameHost host) + private void load(OsuGameBase game, GameHost host) { - notificationOverlay = notification; - this.host = host; version = game.Version; @@ -50,7 +44,7 @@ namespace osu.Desktop.Updater if (latest.TagName != version) { - notificationOverlay.Post(new SimpleNotification + Notifications.Post(new SimpleNotification { Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n" + "Click here to download the new version, which can be installed over the top of your existing installation", @@ -82,6 +76,10 @@ namespace osu.Desktop.Updater case RuntimeInfo.Platform.MacOsx: bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip")); break; + + case RuntimeInfo.Platform.Android: + bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk")); + break; } return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl; diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs new file mode 100644 index 0000000000..cfca7dc858 --- /dev/null +++ b/osu.Game/Updater/UpdateManager.cs @@ -0,0 +1,67 @@ +// 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.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; + +namespace osu.Game.Updater +{ + public abstract class UpdateManager : CompositeDrawable + { + [Resolved] + private OsuConfigManager config { get; set; } + + [Resolved] + private OsuGameBase game { get; set; } + + [Resolved] + protected NotificationOverlay Notifications { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + var version = game.Version; + var lastVersion = config.Get(OsuSetting.Version); + + if (game.IsDeployedBuild && version != lastVersion) + { + config.Set(OsuSetting.Version, version); + + // only show a notification if we've previously saved a version to the config file (ie. not the first run). + if (!string.IsNullOrEmpty(lastVersion)) + Notifications.Post(new UpdateCompleteNotification(version)); + } + } + + private class UpdateCompleteNotification : SimpleNotification + { + private readonly string version; + + public UpdateCompleteNotification(string version) + { + this.version = version; + Text = $"You are now running osu!lazer {version}.\nClick to see what's new!"; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay) + { + Icon = FontAwesome.Solid.CheckSquare; + IconBackgound.Colour = colours.BlueDark; + + Activated = delegate + { + notificationOverlay.Hide(); + changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version); + return true; + }; + } + } + } +} From 07ec163daa856235a5046d2428b2a924c41478bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 18:12:04 +0900 Subject: [PATCH 107/966] Fix version fallback logic --- osu.Android/OsuGameAndroid.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs index aca36b59aa..a91c010809 100644 --- a/osu.Android/OsuGameAndroid.cs +++ b/osu.Android/OsuGameAndroid.cs @@ -4,6 +4,7 @@ using System; using Android.App; using osu.Game; +using osu.Game.Updater; namespace osu.Android { @@ -13,10 +14,11 @@ namespace osu.Android { get { - string versionName = Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0).VersionCode.ToString(); + var packageInfo = Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0); try { + string versionName = packageInfo.VersionCode.ToString(); // undo play store version garbling return new Version(int.Parse(versionName.Substring(0, 4)), int.Parse(versionName.Substring(4, 4)), int.Parse(versionName.Substring(8, 1))); } @@ -24,8 +26,15 @@ namespace osu.Android { } - return new Version(versionName); + return new Version(packageInfo.VersionName); } } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Add(new SimpleUpdateManager()); + } } } \ No newline at end of file From 84d9f98ff1cfde97c4d51b264f11d7d226f243ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 18:15:57 +0900 Subject: [PATCH 108/966] fixup! Move post-update notification logic to UpdateManager base class --- osu.Game/Updater/UpdateManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index cfca7dc858..e256cdbe45 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -20,7 +20,7 @@ namespace osu.Game.Updater private OsuGameBase game { get; set; } [Resolved] - protected NotificationOverlay Notifications { get; set; } + protected NotificationOverlay Notifications { get; private set; } protected override void LoadComplete() { From df692b091c415ee0c9090d00698130368023626b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Sep 2019 18:22:02 +0900 Subject: [PATCH 109/966] Make LabelledComponent generic --- .../UserInterface/TestSceneLabelledComponent.cs | 8 ++++---- osu.Game.Tournament/Screens/SetupScreen.cs | 2 +- .../LabelledComponents/LabelledComponent.cs | 11 ++++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs index 73e0191adb..a762d561c2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep("create component", () => { - LabelledComponent component; + LabelledComponent component; Child = new Container { @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.Centre, Width = 500, AutoSizeAxes = Axes.Y, - Child = component = padded ? (LabelledComponent)new PaddedLabelledComponent() : new NonPaddedLabelledComponent(), + Child = component = padded ? (LabelledComponent)new PaddedLabelledComponent() : new NonPaddedLabelledComponent(), }; component.Label = "a sample component"; @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); } - private class PaddedLabelledComponent : LabelledComponent + private class PaddedLabelledComponent : LabelledComponent { public PaddedLabelledComponent() : base(true) @@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class NonPaddedLabelledComponent : LabelledComponent + private class NonPaddedLabelledComponent : LabelledComponent { public NonPaddedLabelledComponent() : base(false) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 1cb4917790..7a44e7a0e1 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -89,7 +89,7 @@ namespace osu.Game.Tournament.Screens }; } - private class ActionableInfo : LabelledComponent + private class ActionableInfo : LabelledComponent { private OsuButton button; diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs index 19e9c329d6..770065cb0e 100644 --- a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs +++ b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs @@ -11,7 +11,8 @@ using osuTK; namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents { - public abstract class LabelledComponent : CompositeDrawable + public abstract class LabelledComponent : CompositeDrawable + where T : Drawable { protected const float CONTENT_PADDING_VERTICAL = 10; protected const float CONTENT_PADDING_HORIZONTAL = 15; @@ -20,15 +21,15 @@ namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents /// /// The component that is being displayed. /// - protected readonly Drawable Component; + protected readonly T Component; private readonly OsuTextFlowContainer labelText; private readonly OsuTextFlowContainer descriptionText; /// - /// Creates a new . + /// Creates a new . /// - /// Whether the component should be padded or should be expanded to the bounds of this . + /// Whether the component should be padded or should be expanded to the bounds of this . protected LabelledComponent(bool padded) { RelativeSizeAxes = Axes.X; @@ -127,6 +128,6 @@ namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents /// Creates the component that should be displayed. /// /// The component. - protected abstract Drawable CreateComponent(); + protected abstract T CreateComponent(); } } From 6b702eb6de7820dcb4245db7f0fa737731bdf3f9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Sep 2019 18:25:17 +0900 Subject: [PATCH 110/966] Update with generic labelledcomponent --- .../Visual/UserInterface/TestSceneLabelledTextBox.cs | 3 ++- .../Setup/Components/LabelledComponents/LabelledTextBox.cs | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs index f9a5369576..5c5b1262a6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; namespace osu.Game.Tests.Visual.UserInterface @@ -27,7 +28,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep("create component", () => { - LabelledComponent component; + LabelledComponent component; Child = new Container { diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs index 992371fedf..67bacea9f8 100644 --- a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs @@ -9,12 +9,10 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents { - public class LabelledTextBox : LabelledComponent + public class LabelledTextBox : LabelledComponent { public event TextBox.OnCommitHandler OnCommit; - protected new OsuTextBox Component => (OsuTextBox)base.Component; - public LabelledTextBox() : base(false) { @@ -41,7 +39,7 @@ namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents Component.BorderColour = colours.Blue; } - protected override Drawable CreateComponent() => new OsuTextBox + protected override OsuTextBox CreateComponent() => new OsuTextBox { Anchor = Anchor.Centre, Origin = Anchor.Centre, From c226d52b53acbdb84003a736f81488b688b2f01a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 18:34:54 +0900 Subject: [PATCH 111/966] Don't automatic download for now --- osu.Game/Updater/SimpleUpdateManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs index eec27d3325..4789ac94d2 100644 --- a/osu.Game/Updater/SimpleUpdateManager.cs +++ b/osu.Game/Updater/SimpleUpdateManager.cs @@ -78,7 +78,8 @@ namespace osu.Game.Updater break; case RuntimeInfo.Platform.Android: - bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk")); + // on our testing device this causes the download to magically disappear. + //bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk")); break; } From 42b60417639455df5bb6d53000f011ce86e38ee3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 18:03:01 +0900 Subject: [PATCH 112/966] Move post-update notification logic to UpdateManager base class --- osu.Desktop/OsuGameDesktop.cs | 1 + osu.Desktop/Overlays/VersionManager.cs | 55 +-------------- osu.Desktop/Updater/SquirrelUpdateManager.cs | 2 +- .../Updater/SimpleUpdateManager.cs | 18 +++-- osu.Game/Updater/UpdateManager.cs | 67 +++++++++++++++++++ 5 files changed, 78 insertions(+), 65 deletions(-) rename {osu.Desktop => osu.Game}/Updater/SimpleUpdateManager.cs (87%) create mode 100644 osu.Game/Updater/UpdateManager.cs diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 761f52f961..7725ee6451 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -17,6 +17,7 @@ using osu.Framework.Logging; using osu.Framework.Platform.Windows; using osu.Framework.Screens; using osu.Game.Screens.Menu; +using osu.Game.Updater; namespace osu.Desktop { diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 51e801c185..6eed46867a 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -8,11 +8,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays; -using osu.Game.Overlays.Notifications; using osuTK; using osuTK.Graphics; @@ -20,17 +17,9 @@ namespace osu.Desktop.Overlays { public class VersionManager : OverlayContainer { - private OsuConfigManager config; - private OsuGameBase game; - private NotificationOverlay notificationOverlay; - [BackgroundDependencyLoader] - private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config) + private void load(OsuColour colours, TextureStore textures, OsuGameBase game) { - notificationOverlay = notification; - this.config = config; - this.game = game; - AutoSizeAxes = Axes.Both; Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; @@ -85,48 +74,6 @@ namespace osu.Desktop.Overlays }; } - protected override void LoadComplete() - { - base.LoadComplete(); - - var version = game.Version; - var lastVersion = config.Get(OsuSetting.Version); - - if (game.IsDeployedBuild && version != lastVersion) - { - config.Set(OsuSetting.Version, version); - - // only show a notification if we've previously saved a version to the config file (ie. not the first run). - if (!string.IsNullOrEmpty(lastVersion)) - notificationOverlay.Post(new UpdateCompleteNotification(version)); - } - } - - private class UpdateCompleteNotification : SimpleNotification - { - private readonly string version; - - public UpdateCompleteNotification(string version) - { - this.version = version; - Text = $"You are now running osu!lazer {version}.\nClick to see what's new!"; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay) - { - Icon = FontAwesome.Solid.CheckSquare; - IconBackgound.Colour = colours.BlueDark; - - Activated = delegate - { - notificationOverlay.Hide(); - changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version); - return true; - }; - } - } - protected override void PopIn() { this.FadeIn(1400, Easing.OutQuint); diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index fa41c061b5..60b47a8b3a 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -20,7 +20,7 @@ using LogLevel = Splat.LogLevel; namespace osu.Desktop.Updater { - public class SquirrelUpdateManager : Component + public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager { private UpdateManager updateManager; private NotificationOverlay notificationOverlay; diff --git a/osu.Desktop/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs similarity index 87% rename from osu.Desktop/Updater/SimpleUpdateManager.cs rename to osu.Game/Updater/SimpleUpdateManager.cs index 5184791de1..eec27d3325 100644 --- a/osu.Desktop/Updater/SimpleUpdateManager.cs +++ b/osu.Game/Updater/SimpleUpdateManager.cs @@ -6,31 +6,25 @@ using System.Threading.Tasks; using Newtonsoft.Json; using osu.Framework; using osu.Framework.Allocation; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.IO.Network; using osu.Framework.Platform; -using osu.Game; -using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -namespace osu.Desktop.Updater +namespace osu.Game.Updater { /// /// An update manager that shows notifications if a newer release is detected. /// Installation is left up to the user. /// - internal class SimpleUpdateManager : CompositeDrawable + public class SimpleUpdateManager : UpdateManager { - private NotificationOverlay notificationOverlay; private string version; private GameHost host; [BackgroundDependencyLoader] - private void load(NotificationOverlay notification, OsuGameBase game, GameHost host) + private void load(OsuGameBase game, GameHost host) { - notificationOverlay = notification; - this.host = host; version = game.Version; @@ -50,7 +44,7 @@ namespace osu.Desktop.Updater if (latest.TagName != version) { - notificationOverlay.Post(new SimpleNotification + Notifications.Post(new SimpleNotification { Text = $"A newer release of osu! has been found ({version} → {latest.TagName}).\n\n" + "Click here to download the new version, which can be installed over the top of your existing installation", @@ -82,6 +76,10 @@ namespace osu.Desktop.Updater case RuntimeInfo.Platform.MacOsx: bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip")); break; + + case RuntimeInfo.Platform.Android: + bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk")); + break; } return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl; diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs new file mode 100644 index 0000000000..e256cdbe45 --- /dev/null +++ b/osu.Game/Updater/UpdateManager.cs @@ -0,0 +1,67 @@ +// 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.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; + +namespace osu.Game.Updater +{ + public abstract class UpdateManager : CompositeDrawable + { + [Resolved] + private OsuConfigManager config { get; set; } + + [Resolved] + private OsuGameBase game { get; set; } + + [Resolved] + protected NotificationOverlay Notifications { get; private set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + var version = game.Version; + var lastVersion = config.Get(OsuSetting.Version); + + if (game.IsDeployedBuild && version != lastVersion) + { + config.Set(OsuSetting.Version, version); + + // only show a notification if we've previously saved a version to the config file (ie. not the first run). + if (!string.IsNullOrEmpty(lastVersion)) + Notifications.Post(new UpdateCompleteNotification(version)); + } + } + + private class UpdateCompleteNotification : SimpleNotification + { + private readonly string version; + + public UpdateCompleteNotification(string version) + { + this.version = version; + Text = $"You are now running osu!lazer {version}.\nClick to see what's new!"; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay) + { + Icon = FontAwesome.Solid.CheckSquare; + IconBackgound.Colour = colours.BlueDark; + + Activated = delegate + { + notificationOverlay.Hide(); + changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version); + return true; + }; + } + } + } +} From 028c958431728deb42811a92a3993f2382ee49a6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Sep 2019 19:19:43 +0900 Subject: [PATCH 113/966] Initial implementation of a switch button --- .../UserInterface/TestSceneSwitchButton.cs | 20 +++ .../Graphics/UserInterface/SwitchButton.cs | 117 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs create mode 100644 osu.Game/Graphics/UserInterface/SwitchButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs new file mode 100644 index 0000000000..8fe381f141 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs @@ -0,0 +1,20 @@ +// 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; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneSwitchButton : OsuTestScene + { + public TestSceneSwitchButton() + { + Child = new SwitchButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + } +} diff --git a/osu.Game/Graphics/UserInterface/SwitchButton.cs b/osu.Game/Graphics/UserInterface/SwitchButton.cs new file mode 100644 index 0000000000..21712051ef --- /dev/null +++ b/osu.Game/Graphics/UserInterface/SwitchButton.cs @@ -0,0 +1,117 @@ +// 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.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Graphics.UserInterface +{ + public class SwitchButton : Checkbox + { + private const float border_thickness = 4.5f; + private const float padding = 1.25f; + + private readonly Box fill; + private readonly Container switchContainer; + private readonly Drawable switchCircle; + private readonly CircularBorderContainer circularContainer; + + private Color4 enabledColour; + private Color4 disabledColour; + + public SwitchButton() + { + Size = new Vector2(45, 20); + + InternalChild = circularContainer = new CircularBorderContainer + { + RelativeSizeAxes = Axes.Both, + BorderColour = Color4.White, + BorderThickness = border_thickness, + Masking = true, + Children = new Drawable[] + { + fill = new Box + { + RelativeSizeAxes = Axes.Both, + AlwaysPresent = true, + Alpha = 0 + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(border_thickness + padding), + Child = switchContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Child = switchCircle = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + } + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + enabledColour = colours.BlueDark; + disabledColour = colours.Gray3; + + switchContainer.Colour = enabledColour; + fill.Colour = disabledColour; + + updateBorder(); + } + + protected override void OnUserChange(bool value) + { + base.OnUserChange(value); + + if (value) + switchCircle.MoveToX(switchContainer.DrawWidth - switchCircle.DrawWidth, 200, Easing.OutQuint); + else + switchCircle.MoveToX(0, 200, Easing.OutQuint); + + fill.FadeTo(value ? 1 : 0, 250, Easing.OutQuint); + + updateBorder(); + } + + protected override bool OnHover(HoverEvent e) + { + updateBorder(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateBorder(); + base.OnHoverLost(e); + } + + private void updateBorder() + { + circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0)); + } + + private class CircularBorderContainer : CircularContainer + { + public void TransformBorderTo(SRGBColour colour) + => this.TransformTo(nameof(BorderColour), colour, 250, Easing.OutQuint); + } + } +} From f493f1c71d2bee7242b6a4d552bc1ce0f3f05df7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 19:00:26 +0900 Subject: [PATCH 114/966] Move new components to v2 namespace --- .../Visual/UserInterface/TestSceneLabelledComponent.cs | 2 +- .../Visual/UserInterface/TestSceneLabelledTextBox.cs | 2 +- osu.Game.Tournament/Screens/SetupScreen.cs | 2 +- .../UserInterfaceV2}/LabelledComponent.cs | 3 +-- .../UserInterfaceV2}/LabelledTextBox.cs | 3 +-- 5 files changed, 5 insertions(+), 7 deletions(-) rename osu.Game/{Screens/Edit/Setup/Components/LabelledComponents => Graphics/UserInterfaceV2}/LabelledComponent.cs (98%) rename osu.Game/{Screens/Edit/Setup/Components/LabelledComponents => Graphics/UserInterfaceV2}/LabelledTextBox.cs (93%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs index a762d561c2..700adad9cb 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; -using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; +using osu.Game.Graphics.UserInterfaceV2; using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs index 5c5b1262a6..53a2bfabbc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs @@ -8,7 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Tests.Visual.UserInterface { diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 7a44e7a0e1..091a837745 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -7,9 +7,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Overlays; -using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; using osu.Game.Tournament.IPC; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs similarity index 98% rename from osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs rename to osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs index 770065cb0e..2e659825b7 100644 --- a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledComponent.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs @@ -5,11 +5,10 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; -namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents +namespace osu.Game.Graphics.UserInterfaceV2 { public abstract class LabelledComponent : CompositeDrawable where T : Drawable diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs similarity index 93% rename from osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs rename to osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs index 67bacea9f8..50d2a14482 100644 --- a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs @@ -4,10 +4,9 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents +namespace osu.Game.Graphics.UserInterfaceV2 { public class LabelledTextBox : LabelledComponent { From afa043aa7de522e6436276d2c000f9820800b970 Mon Sep 17 00:00:00 2001 From: LeNitrous Date: Tue, 24 Sep 2019 18:17:27 +0800 Subject: [PATCH 115/966] always use default samples --- osu.Game/Screens/Menu/IntroCircles.cs | 5 +++-- osu.Game/Screens/Menu/IntroScreen.cs | 30 ++----------------------- osu.Game/Screens/Menu/IntroTriangles.cs | 4 ++-- 3 files changed, 7 insertions(+), 32 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index a861d54663..6c643860a0 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Screens; using osu.Framework.Graphics; @@ -17,10 +18,10 @@ namespace osu.Game.Screens.Menu private const double delay_step_two = 600; [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { if (MenuVoice.Value) - SetWelcome(); + Welcome = audio.Samples.Get(@"welcome"); } protected override void LogoArriving(OsuLogo logo, bool resuming) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 651fa7583d..c81fef6436 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -9,14 +9,11 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.MathUtils; using osu.Framework.Screens; -using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.IO.Archives; using osu.Game.Screens.Backgrounds; using osu.Game.Skinning; -using osu.Game.Online.API; -using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -51,14 +48,10 @@ namespace osu.Game.Screens.Menu public new Bindable Beatmap => beatmap; - protected Bindable User; - - protected Bindable Skin; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); [BackgroundDependencyLoader] - private void load(OsuConfigManager config, IAPIProvider api, SkinManager skinManager, BeatmapManager beatmaps, Framework.Game game) + private void load(OsuConfigManager config, SkinManager skinManager, BeatmapManager beatmaps, Framework.Game game) { // prevent user from changing beatmap while the intro is still runnning. beatmap = base.Beatmap.BeginLease(false); @@ -66,10 +59,7 @@ namespace osu.Game.Screens.Menu MenuVoice = config.GetBindable(OsuSetting.MenuVoice); MenuMusic = config.GetBindable(OsuSetting.MenuMusic); - User = api.LocalUser.GetBoundCopy(); - Skin = skinManager.CurrentSkin.GetBoundCopy(); - - Skin.BindValueChanged(_ => updateSeeya(), true); + seeya = audio.Samples.Get(@"seeya"); BeatmapSetInfo setInfo = null; @@ -98,22 +88,6 @@ namespace osu.Game.Screens.Menu Track = IntroBeatmap.Track; } - private void updateSeeya() - { - if (User.Value?.IsSupporter ?? false) - seeya = Skin.Value.GetSample(new SampleInfo("seeya")) ?? audio.Samples.Get(@"seeya"); - else - seeya = audio.Samples.Get(@"seeya"); - } - - protected void SetWelcome() - { - if (User.Value?.IsSupporter ?? false) - Welcome = Skin.Value.GetSample(new SampleInfo("welcome")) ?? audio.Samples.Get(@"welcome"); - else - Welcome = audio.Samples.Get(@"welcome"); - } - /// /// Whether we have loaded the menu previously. /// diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 5b49a81a5a..590069ab43 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -41,10 +41,10 @@ namespace osu.Game.Screens.Menu private BackgroundScreenDefault background; [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { if (MenuVoice.Value && !MenuMusic.Value) - SetWelcome(); + Welcome = audio.Samples.Get(@"welcome"); } protected override void LogoArriving(OsuLogo logo, bool resuming) From e78f134b90792a65e0b8e7d59236c32ea415f156 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Sep 2019 19:35:42 +0900 Subject: [PATCH 116/966] Mark configuration lookup test headless --- osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index bbcc4140a9..578030748b 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Skinning; using osu.Game.Tests.Visual; @@ -17,6 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Skins { [TestFixture] + [HeadlessTest] public class TestSceneSkinConfigurationLookup : OsuTestScene { private LegacySkin source1; From 4a59e3351edb6f5b9eb12c398e43bbe1c43be3a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Sep 2019 02:42:12 +0900 Subject: [PATCH 117/966] Update beatmap carousel tests code style Also fixes one issue I spotted in BeatmapCarousel related to incorrectly holding a selection after new sets are loaded. --- .../SongSelect/TestSceneBeatmapCarousel.cs | 98 +++++++++++-------- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 + 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 71399106f4..16e873a84c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.SongSelect private readonly Stack selectedSets = new Stack(); private readonly HashSet eagerSelectedIDs = new HashSet(); - private BeatmapInfo currentSelection; + private BeatmapInfo currentSelection => carousel.SelectedBeatmap; private const int set_count = 5; @@ -56,37 +56,26 @@ namespace osu.Game.Tests.Visual.SongSelect { RelativeSizeAxes = Axes.Both, }); - - List beatmapSets = new List(); - - for (int i = 1; i <= set_count; i++) - beatmapSets.Add(createTestBeatmapSet(i)); - - carousel.SelectionChanged = s => currentSelection = s; - - loadBeatmaps(beatmapSets); - - testTraversal(); - testFiltering(); - testRandom(); - testAddRemove(); - testSorting(); - - testRemoveAll(); - testEmptyTraversal(); - testHiding(); - testSelectingFilteredRuleset(); - testCarouselRootIsRandom(); } - private void loadBeatmaps(List beatmapSets) + private void loadBeatmaps(List beatmapSets = null) { + if (beatmapSets == null) + { + beatmapSets = new List(); + + for (int i = 1; i <= set_count; i++) + beatmapSets.Add(createTestBeatmapSet(i)); + } + bool changed = false; AddStep($"Load {beatmapSets.Count} Beatmaps", () => { + carousel.Filter(new FilterCriteria()); carousel.BeatmapSetsChanged = () => changed = true; carousel.BeatmapSets = beatmapSets; }); + AddUntilStep("Wait for load", () => changed); } @@ -173,8 +162,11 @@ namespace osu.Game.Tests.Visual.SongSelect /// /// Test keyboard traversal /// - private void testTraversal() + [Test] + public void TestTraversal() { + loadBeatmaps(); + advanceSelection(direction: 1, diff: false); checkSelected(1, 1); @@ -199,8 +191,11 @@ namespace osu.Game.Tests.Visual.SongSelect /// /// Test filtering /// - private void testFiltering() + [Test] + public void TestFiltering() { + loadBeatmaps(); + // basic filtering setSelected(1, 1); @@ -262,8 +257,11 @@ namespace osu.Game.Tests.Visual.SongSelect /// /// Test random non-repeating algorithm /// - private void testRandom() + [Test] + public void TestRandom() { + loadBeatmaps(); + setSelected(1, 1); nextRandom(); @@ -299,8 +297,11 @@ namespace osu.Game.Tests.Visual.SongSelect /// /// Test adding and removing beatmap sets /// - private void testAddRemove() + [Test] + public void TestAddRemove() { + loadBeatmaps(); + AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 1))); AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 2))); @@ -322,16 +323,22 @@ namespace osu.Game.Tests.Visual.SongSelect /// /// Test sorting /// - private void testSorting() + [Test] + public void TestSorting() { + loadBeatmaps(); + AddStep("Sort by author", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Author }, false)); AddAssert("Check zzzzz is at bottom", () => carousel.BeatmapSets.Last().Metadata.AuthorString == "zzzzz"); AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); AddAssert($"Check #{set_count} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Title.EndsWith($"#{set_count}!")); } - private void testRemoveAll() + [Test] + public void TestRemoveAll() { + loadBeatmaps(); + setSelected(2, 1); AddAssert("Selection is non-null", () => currentSelection != null); @@ -353,8 +360,11 @@ namespace osu.Game.Tests.Visual.SongSelect checkNoSelection(); } - private void testEmptyTraversal() + [Test] + public void TestEmptyTraversal() { + loadBeatmaps(new List()); + advanceSelection(direction: 1, diff: false); checkNoSelection(); @@ -368,11 +378,18 @@ namespace osu.Game.Tests.Visual.SongSelect checkNoSelection(); } - private void testHiding() + [Test] + public void TestHiding() { - var hidingSet = createTestBeatmapSet(1); - hidingSet.Beatmaps[1].Hidden = true; - AddStep("Add set with diff 2 hidden", () => carousel.UpdateBeatmapSet(hidingSet)); + BeatmapSetInfo hidingSet = null; + + AddStep("Add set with diff 2 hidden", () => + { + hidingSet = createTestBeatmapSet(1); + hidingSet.Beatmaps[1].Hidden = true; + carousel.UpdateBeatmapSet(hidingSet); + }); + setSelected(1, 1); checkVisibleItemCount(true, 2); @@ -402,7 +419,8 @@ namespace osu.Game.Tests.Visual.SongSelect } } - private void testSelectingFilteredRuleset() + [Test] + public void TestSelectingFilteredRuleset() { var testMixed = createTestBeatmapSet(set_count + 1); AddStep("add mixed ruleset beatmapset", () => @@ -437,14 +455,16 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); } - private void testCarouselRootIsRandom() + [Test] + public void TestCarouselRootIsRandom() { - List beatmapSets = new List(); + List manySets = new List(); for (int i = 1; i <= 50; i++) - beatmapSets.Add(createTestBeatmapSet(i)); + manySets.Add(createTestBeatmapSet(i)); + + loadBeatmaps(manySets); - loadBeatmaps(beatmapSets); advanceSelection(direction: 1, diff: false); checkNonmatchingFilter(); checkNonmatchingFilter(); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 23c581c6f9..c3436ffd45 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -82,6 +82,9 @@ namespace osu.Game.Screens.Select var _ = newRoot.Drawables; root = newRoot; + if (selectedBeatmapSet != null && !beatmapSets.Contains(selectedBeatmapSet.BeatmapSet)) + selectedBeatmapSet = null; + scrollableContent.Clear(false); itemsCache.Invalidate(); scrollPositionCache.Invalidate(); From 56b460365b7cd5b96ba03ba7ca118fb8db6bb9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Sep 2019 20:34:09 +0200 Subject: [PATCH 118/966] Add bar line anchoring checks in mania test stage Add steps checking bar line anchoring in the mania Stage visual test to reproduce the regression in #6215 and prevent it from happening in the future. --- osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs index e7fd601abe..56401dd082 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs @@ -67,6 +67,8 @@ namespace osu.Game.Rulesets.Mania.Tests AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.TopCentre)); AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.BottomCentre)); + AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[0], Anchor.TopCentre)); + AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[1], Anchor.BottomCentre)); AddStep("flip direction", () => { @@ -76,10 +78,14 @@ namespace osu.Game.Rulesets.Mania.Tests AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.BottomCentre)); AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.TopCentre)); + AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[0], Anchor.BottomCentre)); + AddAssert("check bar anchors", () => barsInStageAreAnchored(stages[1], Anchor.TopCentre)); } private bool notesInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor); + private bool barsInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.AllHitObjects.Where(obj => obj is DrawableBarLine).All(o => o.Anchor == anchor); + private void createNote() { foreach (var stage in stages) From 09864d7f0edb3a6164d2d384acc977c2e8795ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Sep 2019 21:42:40 +0200 Subject: [PATCH 119/966] Add bar line visual check in taiko playfield test Add a step checking alignment of a centre and a bar line in taiko playfield. Purely visual test without asserts. --- osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs index 3aa461e779..cbbf5b0c09 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs @@ -53,6 +53,11 @@ namespace osu.Game.Rulesets.Taiko.Tests AddStep("Strong Rim", () => addRimHit(true)); AddStep("Add bar line", () => addBarLine(false)); AddStep("Add major bar line", () => addBarLine(true)); + AddStep("Add centre w/ bar line", () => + { + addCentreHit(false); + addBarLine(true); + }); AddStep("Height test 1", () => changePlayfieldSize(1)); AddStep("Height test 2", () => changePlayfieldSize(2)); AddStep("Height test 3", () => changePlayfieldSize(3)); From d013b73d33082c3f1471bc922c4d77147122c81d Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 25 Sep 2019 01:25:05 +0300 Subject: [PATCH 120/966] Move in-memory logic to a base class --- .../Configuration/InMemoryConfigManager.cs | 22 +++++++++++++++++++ osu.Game/Configuration/SessionStatics.cs | 10 +++------ 2 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Configuration/InMemoryConfigManager.cs diff --git a/osu.Game/Configuration/InMemoryConfigManager.cs b/osu.Game/Configuration/InMemoryConfigManager.cs new file mode 100644 index 0000000000..b0dc6b0e9c --- /dev/null +++ b/osu.Game/Configuration/InMemoryConfigManager.cs @@ -0,0 +1,22 @@ +// 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.Configuration; + +namespace osu.Game.Configuration +{ + public class InMemoryConfigManager : ConfigManager + where T : struct + { + public InMemoryConfigManager() + { + InitialiseDefaults(); + } + + protected override void PerformLoad() + { + } + + protected override bool PerformSave() => true; + } +} diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 0c1ea1e568..b4b5e914bb 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -1,18 +1,14 @@ // 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.Configuration; - namespace osu.Game.Configuration { - public class SessionStatics : ConfigManager + public class SessionStatics : InMemoryConfigManager { - // This is an in-memory store. - protected override void PerformLoad() + protected override void InitialiseDefaults() { + Set(Statics.LoginOverlayDisplayed, false); } - - protected override bool PerformSave() => true; } public enum Statics From cde7f49db1b37d3325b64f0ceddd312476e3f2c8 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 25 Sep 2019 01:26:02 +0300 Subject: [PATCH 121/966] Use direct get and set instead --- osu.Game/Screens/Menu/MainMenu.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 1834221d35..98ceb315a2 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -200,12 +200,10 @@ namespace osu.Game.Screens.Menu bool displayLogin() { - var loginDisplayed = statics.GetBindable(Statics.LoginOverlayDisplayed); - - if (!loginDisplayed.Value) + if (!statics.Get(Statics.LoginOverlayDisplayed)) { Scheduler.AddDelayed(() => login?.Show(), 500); - loginDisplayed.Value = true; + statics.Set(Statics.LoginOverlayDisplayed, true); } return true; From 9323df26a1cafa6fa90e316bfa659fcb5584fa13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Sep 2019 23:03:55 +0200 Subject: [PATCH 122/966] Decouple bar line hitobjects from generator Introduce an IBarLine interface, which together with generic constraints helps decouple BarLineGenerator from the actual hitobject types it creates. Thanks to this, all rulesets that want bar lines can provide an implementation of IBarLine that also derives from the base hitobject class. This allows DrawableBarLines in taiko and mania to be migrated back to DrawableTaikoHitObject and DrawableManiaHitObject base classes respectively. This in turn resolves #6215 without code duplication, since the missing anchoring application is now done in mania's DrawableBarLine through deriving from DrawableManiaHitObject. --- osu.Game.Rulesets.Mania/Objects/BarLine.cs | 12 ++++++++++ .../Objects/Drawables/DrawableBarLine.cs | 3 +-- .../UI/DrawableManiaRuleset.cs | 2 +- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 1 - osu.Game.Rulesets.Taiko/Objects/BarLine.cs | 12 ++++++++++ .../UI/DrawableTaikoRuleset.cs | 2 +- osu.Game/Rulesets/Objects/BarLine.cs | 16 -------------- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 7 +++--- osu.Game/Rulesets/Objects/IBarLine.cs | 22 +++++++++++++++++++ 9 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Objects/BarLine.cs create mode 100644 osu.Game.Rulesets.Taiko/Objects/BarLine.cs delete mode 100644 osu.Game/Rulesets/Objects/BarLine.cs create mode 100644 osu.Game/Rulesets/Objects/IBarLine.cs diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs new file mode 100644 index 0000000000..0981b028b2 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs @@ -0,0 +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 osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Mania.Objects +{ + public class BarLine : ManiaHitObject, IBarLine + { + public bool Major { get; set; } + } +} diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index be21610525..56bc797c7f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -4,7 +4,6 @@ using osuTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osuTK.Graphics; @@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// Visualises a . Although this derives DrawableManiaHitObject, /// this does not handle input/sound like a normal hit object. /// - public class DrawableBarLine : DrawableHitObject + public class DrawableBarLine : DrawableManiaHitObject { /// /// Height of major bar line triangles. diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 29863fba2e..d371c1f7a8 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.UI public DrawableManiaRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { - BarLines = new BarLineGenerator(Beatmap).BarLines; + BarLines = new BarLineGenerator(Beatmap).BarLines; } [BackgroundDependencyLoader] diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 12faa499ad..5ab07416a6 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; using osuTK; diff --git a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs new file mode 100644 index 0000000000..2afbbc737c --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs @@ -0,0 +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 osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Taiko.Objects +{ + public class BarLine : TaikoHitObject, IBarLine + { + public bool Major { get; set; } + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 5caa9e4626..fc109bf6a6 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load() { - new BarLineGenerator(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar))); + new BarLineGenerator(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar))); } public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this); diff --git a/osu.Game/Rulesets/Objects/BarLine.cs b/osu.Game/Rulesets/Objects/BarLine.cs deleted file mode 100644 index a5c716e127..0000000000 --- a/osu.Game/Rulesets/Objects/BarLine.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Rulesets.Objects -{ - /// - /// A hit object representing the end of a bar. - /// - public class BarLine : HitObject - { - /// - /// Whether this barline is a prominent beat (based on time signature of beatmap). - /// - public bool Major; - } -} diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index ce571d7b17..4f9395435e 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -10,12 +10,13 @@ using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Objects { - public class BarLineGenerator + public class BarLineGenerator + where TBarLine : class, IBarLine, new() { /// /// The generated bar lines. /// - public readonly List BarLines = new List(); + public readonly List BarLines = new List(); /// /// Constructs and generates bar lines for provided beatmap. @@ -46,7 +47,7 @@ namespace osu.Game.Rulesets.Objects for (double t = currentTimingPoint.Time; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++) { - BarLines.Add(new BarLine + BarLines.Add(new TBarLine { StartTime = t, Major = currentBeat % (int)currentTimingPoint.TimeSignature == 0 diff --git a/osu.Game/Rulesets/Objects/IBarLine.cs b/osu.Game/Rulesets/Objects/IBarLine.cs new file mode 100644 index 0000000000..14df80e3b9 --- /dev/null +++ b/osu.Game/Rulesets/Objects/IBarLine.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Objects +{ + /// + /// Interface for bar line hitobjects. + /// Used to decouple bar line generation from ruleset-specific rendering/drawing hierarchies. + /// + public interface IBarLine + { + /// + /// The time position of the bar. + /// + double StartTime { set; } + + /// + /// Whether this bar line is a prominent beat (based on time signature of beatmap). + /// + bool Major { set; } + } +} From 7fab1a4337c4db0094e4179fb34037984f1d322b Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 24 Sep 2019 16:06:33 -0700 Subject: [PATCH 123/966] Truncate long metadata on beatmap info wedge --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 22 +++++++++++++++------ osu.Game/Screens/Select/SongSelect.cs | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 65ecd7b812..6c3eed8610 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -31,7 +31,9 @@ namespace osu.Game.Screens.Select { public class BeatmapInfoWedge : OverlayContainer { - private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); + private const float shear_width = 36.75f; + + private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.wedged_container_size.Y, 0); private readonly IBindable ruleset = new Bindable(); @@ -200,14 +202,17 @@ namespace osu.Game.Screens.Select Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, Direction = FillDirection.Vertical, - Margin = new MarginPadding { Top = 10, Left = 25, Right = 10, Bottom = 20 }, - AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 10, Left = 25, Right = shear_width * 2.5f, Bottom = 20 }, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, Children = new Drawable[] { VersionLabel = new OsuSpriteText { Text = beatmapInfo.Version, Font = OsuFont.GetFont(size: 24, italics: true), + RelativeSizeAxes = Axes.X, + Truncate = true, }, } }, @@ -217,7 +222,7 @@ namespace osu.Game.Screens.Select Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Direction = FillDirection.Vertical, - Margin = new MarginPadding { Top = 14, Left = 10, Right = 18, Bottom = 20 }, + Padding = new MarginPadding { Top = 14, Left = 10, Right = shear_width / 2, Bottom = 20 }, AutoSizeAxes = Axes.Both, Children = new Drawable[] { @@ -236,17 +241,22 @@ namespace osu.Game.Screens.Select Origin = Anchor.TopLeft, Y = -22, Direction = FillDirection.Vertical, - Margin = new MarginPadding { Top = 15, Left = 25, Right = 10, Bottom = 20 }, - AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 15, Left = 25, Right = shear_width, Bottom = 20 }, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, Children = new Drawable[] { TitleLabel = new OsuSpriteText { Font = OsuFont.GetFont(size: 28, italics: true), + RelativeSizeAxes = Axes.X, + Truncate = true, }, ArtistLabel = new OsuSpriteText { Font = OsuFont.GetFont(size: 17, italics: true), + RelativeSizeAxes = Axes.X, + Truncate = true, }, MapperContainer = new FillFlowContainer { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index fca801ce78..6c0d8a0f36 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Select { public abstract class SongSelect : OsuScreen, IKeyBindingHandler { - private static readonly Vector2 wedged_container_size = new Vector2(0.5f, 245); + public static readonly Vector2 wedged_container_size = new Vector2(0.5f, 245); protected const float BACKGROUND_BLUR = 20; private const float left_area_padding = 20; From 8efab559c8d65138c2a38097970797957f396233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 25 Sep 2019 01:13:42 +0200 Subject: [PATCH 124/966] Remove unused using directives --- osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs | 1 - osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 1 - .../Objects/Drawables/DrawableBarLineMajor.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs index 56401dd082..d5fd2808b8 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs @@ -15,7 +15,6 @@ using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Tests.Visual; using osuTK; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 98a4b7d0b6..a28de7ea58 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -12,7 +12,6 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs index f5b75a781b..4d3a1a3f8a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs @@ -5,7 +5,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osuTK; using osu.Framework.Graphics.Shapes; -using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { From 8efba255c383acd4114b1625939eaf745bb59cbd Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 24 Sep 2019 16:21:08 -0700 Subject: [PATCH 125/966] Add truncation test --- .../SongSelect/TestSceneBeatmapInfoWedge.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index 932e114580..cda6bedf5d 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -127,6 +127,12 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("check no info labels", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); } + [Test] + public void testTruncation() + { + selectBeatmap(createLongMetadata()); + } + private void selectBeatmap([CanBeNull] IBeatmap b) { BeatmapInfoWedge.BufferedWedgeInfo infoBefore = null; @@ -166,6 +172,25 @@ namespace osu.Game.Tests.Visual.SongSelect }; } + private IBeatmap createLongMetadata() + { + return new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + AuthorString = $"WWWWWWWWWWWWWWW", + Artist = $"Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Artist", + Source = $"Verrrrry long Source", + Title = $"Verrrrry long Title" + }, + Version = $"Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version", + Status = BeatmapSetOnlineStatus.Graveyard, + }, + }; + } + private class TestBeatmapInfoWedge : BeatmapInfoWedge { public new BufferedWedgeInfo Info => base.Info; From cc6030ca14d3f6377c657afeb44faa96bca3bbd2 Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 24 Sep 2019 16:23:36 -0700 Subject: [PATCH 126/966] Update beatmap info wedge tests --- .../Visual/SongSelect/TestSceneBeatmapInfoWedge.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index cda6bedf5d..017e9c527b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -75,7 +75,6 @@ namespace osu.Game.Tests.Visual.SongSelect testBeatmapLabels(instance); - // TODO: adjust cases once more info is shown for other gamemodes switch (instance) { case OsuRuleset _: @@ -99,8 +98,6 @@ namespace osu.Game.Tests.Visual.SongSelect break; } } - - testNullBeatmap(); } private void testBeatmapLabels(Ruleset ruleset) @@ -117,7 +114,8 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("check info labels count", () => infoWedge.Info.InfoLabelContainer.Children.Count == expectedCount); } - private void testNullBeatmap() + [Test] + public void testNullBeatmap() { selectBeatmap(null); AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Text)); From 9861b214407a5e4861722b2cfb876bd524db76de Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 24 Sep 2019 16:28:40 -0700 Subject: [PATCH 127/966] Remove unnecessary padding/margin --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 6c3eed8610..33060e0735 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -202,7 +202,7 @@ namespace osu.Game.Screens.Select Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 10, Left = 25, Right = shear_width * 2.5f, Bottom = 20 }, + Padding = new MarginPadding { Top = 10, Left = 25, Right = shear_width * 2.5f }, AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Children = new Drawable[] @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Select Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 14, Left = 10, Right = shear_width / 2, Bottom = 20 }, + Padding = new MarginPadding { Top = 14, Right = shear_width / 2 }, AutoSizeAxes = Axes.Both, Children = new Drawable[] { @@ -239,9 +239,9 @@ namespace osu.Game.Screens.Select Name = "Centre-aligned metadata", Anchor = Anchor.CentreLeft, Origin = Anchor.TopLeft, - Y = -22, + Y = -7, Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 15, Left = 25, Right = shear_width, Bottom = 20 }, + Padding = new MarginPadding { Left = 25, Right = shear_width }, AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Children = new Drawable[] From 102dbd85bdd4fd4f4589314e3164512502860b51 Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 24 Sep 2019 16:48:22 -0700 Subject: [PATCH 128/966] Fix CI errors --- .../Visual/SongSelect/TestSceneBeatmapInfoWedge.cs | 14 +++++++------- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index 017e9c527b..f49d7a14a6 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.SongSelect } [Test] - public void testNullBeatmap() + public void TestNullBeatmap() { selectBeatmap(null); AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Text)); @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.SongSelect } [Test] - public void testTruncation() + public void TestTruncation() { selectBeatmap(createLongMetadata()); } @@ -178,12 +178,12 @@ namespace osu.Game.Tests.Visual.SongSelect { Metadata = new BeatmapMetadata { - AuthorString = $"WWWWWWWWWWWWWWW", - Artist = $"Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Artist", - Source = $"Verrrrry long Source", - Title = $"Verrrrry long Title" + AuthorString = "WWWWWWWWWWWWWWW", + Artist = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Artist", + Source = "Verrrrry long Source", + Title = "Verrrrry long Title" }, - Version = $"Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version", + Version = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version", Status = BeatmapSetOnlineStatus.Graveyard, }, }; diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 33060e0735..8b360d4a86 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Select { private const float shear_width = 36.75f; - private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.wedged_container_size.Y, 0); + private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.WEDGED_CONTAINER_SIZE.Y, 0); private readonly IBindable ruleset = new Bindable(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6c0d8a0f36..653f62dd15 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Select { public abstract class SongSelect : OsuScreen, IKeyBindingHandler { - public static readonly Vector2 wedged_container_size = new Vector2(0.5f, 245); + public static readonly Vector2 WEDGED_CONTAINER_SIZE = new Vector2(0.5f, 245); protected const float BACKGROUND_BLUR = 20; private const float left_area_padding = 20; @@ -109,7 +109,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = -150 }, - Size = new Vector2(wedged_container_size.X, 1), + Size = new Vector2(WEDGED_CONTAINER_SIZE.X, 1), } } }, @@ -118,11 +118,11 @@ namespace osu.Game.Screens.Select Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, - Size = new Vector2(wedged_container_size.X, 1), + Size = new Vector2(WEDGED_CONTAINER_SIZE.X, 1), Padding = new MarginPadding { Bottom = Footer.HEIGHT, - Top = wedged_container_size.Y + left_area_padding, + Top = WEDGED_CONTAINER_SIZE.Y + left_area_padding, Left = left_area_padding, Right = left_area_padding * 2, }, @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Select Child = Carousel = new BeatmapCarousel { RelativeSizeAxes = Axes.Both, - Size = new Vector2(1 - wedged_container_size.X, 1), + Size = new Vector2(1 - WEDGED_CONTAINER_SIZE.X, 1), Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, SelectionChanged = updateSelectedBeatmap, @@ -182,7 +182,7 @@ namespace osu.Game.Screens.Select }, beatmapInfoWedge = new BeatmapInfoWedge { - Size = wedged_container_size, + Size = WEDGED_CONTAINER_SIZE, RelativeSizeAxes = Axes.X, Margin = new MarginPadding { From 2089f6fc42ed65d088712553def79a8078716b8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Sep 2019 14:28:35 +0900 Subject: [PATCH 129/966] Fix potential test fail case --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 16e873a84c..f12a613bf1 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -381,14 +381,10 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestHiding() { - BeatmapSetInfo hidingSet = null; + BeatmapSetInfo hidingSet = createTestBeatmapSet(1); + hidingSet.Beatmaps[1].Hidden = true; - AddStep("Add set with diff 2 hidden", () => - { - hidingSet = createTestBeatmapSet(1); - hidingSet.Beatmaps[1].Hidden = true; - carousel.UpdateBeatmapSet(hidingSet); - }); + loadBeatmaps(new List { hidingSet }); setSelected(1, 1); From c83db94eb7ccbe458da15d6f1d7563e14af0cfba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Sep 2019 15:00:08 +0900 Subject: [PATCH 130/966] Use isolated storage/api --- .../Visual/Menus/TestSceneScreenNavigation.cs | 25 +++++++--------- osu.Game/Online/API/APIRequest.cs | 5 +++- osu.Game/OsuGameBase.cs | 29 ++++++++++++------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index 515f4cdce6..ee160e6a15 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Menus { private const float click_padding = 25; - private GameHost gameHost; + private GameHost host; private TestOsuGame osuGame; private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(click_padding, osuGame.LayoutRectangle.Bottom - click_padding)); @@ -36,9 +36,9 @@ namespace osu.Game.Tests.Visual.Menus private Vector2 optionsButtonPosition => osuGame.ToScreenSpace(new Vector2(click_padding, click_padding)); [BackgroundDependencyLoader] - private void load(GameHost gameHost) + private void load(GameHost host) { - this.gameHost = gameHost; + this.host = host; Child = new Box { @@ -58,8 +58,8 @@ namespace osu.Game.Tests.Visual.Menus osuGame.Dispose(); } - osuGame = new TestOsuGame(); - osuGame.SetHost(gameHost); + osuGame = new TestOsuGame(LocalStorage, API); + osuGame.SetHost(host); Add(osuGame); }); @@ -163,19 +163,16 @@ namespace osu.Game.Tests.Visual.Menus protected override Loader CreateLoader() => new TestLoader(); - private DependencyContainer dependencies; - - private DummyAPIAccess dummyAPI; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + public TestOsuGame(Storage storage, IAPIProvider api) + { + Storage = storage; + API = api; + } protected override void LoadComplete() { base.LoadComplete(); - dependencies.CacheAs(dummyAPI = new DummyAPIAccess()); - - dummyAPI.Login("Rhythm Champion", "osu!"); + API.Login("Rhythm Champion", "osu!"); } } diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index e8eff5a3a9..4f613d5c3c 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -64,7 +64,10 @@ namespace osu.Game.Online.API public void Perform(IAPIProvider api) { if (!(api is APIAccess apiAccess)) - throw new NotSupportedException($"A {nameof(APIAccess)} is required to perform requests."); + { + Fail(new NotSupportedException($"A {nameof(APIAccess)} is required to perform requests.")); + return; + } API = apiAccess; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index d6b8ad3e67..9d1eff4819 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -65,7 +65,7 @@ namespace osu.Game protected RulesetConfigCache RulesetConfigCache; - protected APIAccess API; + protected IAPIProvider API; protected MenuCursorContainer MenuCursorContainer; @@ -73,6 +73,8 @@ namespace osu.Game protected override Container Content => content; + protected Storage Storage { get; set; } + private Bindable beatmap; // cached via load() method [Cached] @@ -123,7 +125,7 @@ namespace osu.Game { Resources.AddStore(new DllResourceStore(@"osu.Game.Resources.dll")); - dependencies.Cache(contextFactory = new DatabaseContextFactory(Host.Storage)); + dependencies.Cache(contextFactory = new DatabaseContextFactory(Storage)); var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore(Resources, @"Textures"))); largeStore.AddStore(Host.CreateTextureLoaderStore(new OnlineStore())); @@ -158,21 +160,21 @@ namespace osu.Game runMigrations(); - dependencies.Cache(SkinManager = new SkinManager(Host.Storage, contextFactory, Host, Audio, new NamespacedResourceStore(Resources, "Skins/Legacy"))); + dependencies.Cache(SkinManager = new SkinManager(Storage, contextFactory, Host, Audio, new NamespacedResourceStore(Resources, "Skins/Legacy"))); dependencies.CacheAs(SkinManager); - API = new APIAccess(LocalConfig); + if (API == null) API = new APIAccess(LocalConfig); - dependencies.CacheAs(API); + dependencies.CacheAs(API); var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures); dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); - dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); + dependencies.Cache(FileStore = new FileStore(contextFactory, 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, API, contextFactory, Host)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host)); + dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap)); // 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 interface to @@ -206,7 +208,8 @@ namespace osu.Game FileStore.Cleanup(); - AddInternal(API); + if (API is APIAccess apiAcces) + AddInternal(apiAcces); AddInternal(RulesetConfigCache); GlobalActionContainer globalBinding; @@ -266,9 +269,13 @@ namespace osu.Game public override void SetHost(GameHost host) { - if (LocalConfig == null) - LocalConfig = new OsuConfigManager(host.Storage); base.SetHost(host); + + if (Storage == null) + Storage = host.Storage; + + if (LocalConfig == null) + LocalConfig = new OsuConfigManager(Storage); } private readonly List fileImporters = new List(); From 8fd1a45a4278389c8b3fdc8e76209218cb4804d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Sep 2019 15:29:02 +0900 Subject: [PATCH 131/966] Change intro displayed for tests As the triangles intro relies on the audio track's clock advancing, we can't use it just yet (CI server has no audio device). This is a temporary workaround for that shortcoming. --- osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index ee160e6a15..17535cae98 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays; @@ -21,6 +22,7 @@ using osu.Game.Screens.Select; using osuTK; using osuTK.Graphics; using osuTK.Input; +using IntroSequence = osu.Game.Configuration.IntroSequence; namespace osu.Game.Tests.Visual.Menus { @@ -61,6 +63,10 @@ namespace osu.Game.Tests.Visual.Menus osuGame = new TestOsuGame(LocalStorage, API); osuGame.SetHost(host); + // todo: this can be removed once we can run audio trakcs without a device present + // see https://github.com/ppy/osu/issues/1302 + osuGame.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles); + Add(osuGame); }); AddUntilStep("Wait for load", () => osuGame.IsLoaded); @@ -161,6 +167,8 @@ namespace osu.Game.Tests.Visual.Menus public new SettingsPanel Settings => base.Settings; + public new OsuConfigManager LocalConfig => base.LocalConfig; + protected override Loader CreateLoader() => new TestLoader(); public TestOsuGame(Storage storage, IAPIProvider api) From 74b2e99247ab38d210d76aac8050aac8533057f6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Sep 2019 16:25:15 +0900 Subject: [PATCH 132/966] Fix invalid cursor trail parts being drawn --- .../UI/Cursor/CursorTrail.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index b32dfd483f..80291c002e 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -40,9 +40,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor for (int i = 0; i < max_sprites; i++) { - // InvalidationID 1 forces an update of each part of the cursor trail the first time ApplyState is run on the draw node - // This is to prevent garbage data from being sent to the vertex shader, resulting in visual issues on some platforms - parts[i].InvalidationID = 1; + // -1 signals that the part is unusable, and should not be drawn + parts[i].InvalidationID = -1; } } @@ -112,7 +111,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor for (int i = 0; i < parts.Length; ++i) { parts[i].Time -= time; - ++parts[i].InvalidationID; + + if (parts[i].InvalidationID != -1) + ++parts[i].InvalidationID; } time = 0; @@ -205,8 +206,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor public TrailDrawNode(CursorTrail source) : base(source) { - for (int i = 0; i < max_sprites; i++) - parts[i].InvalidationID = 0; } public override void ApplyState() @@ -218,11 +217,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor size = Source.partSize; time = Source.time; - for (int i = 0; i < Source.parts.Length; ++i) - { - if (Source.parts[i].InvalidationID > parts[i].InvalidationID) - parts[i] = Source.parts[i]; - } + Source.parts.CopyTo(parts, 0); } public override void Draw(Action vertexAction) @@ -234,6 +229,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor for (int i = 0; i < parts.Length; ++i) { + if (parts[i].InvalidationID == -1) + continue; + vertexBatch.DrawTime = parts[i].Time; Vector2 pos = parts[i].Position; From 261ba5c80ac4b82d5d73ce02c9609fe8bc829783 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Sep 2019 17:42:27 +0900 Subject: [PATCH 133/966] Fix button not transforming correctly in some cases --- .../UserInterface/TestSceneSwitchButton.cs | 30 +++++++++++++++++-- .../Graphics/UserInterface/SwitchButton.cs | 19 ++++++------ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs index 8fe381f141..bf9071b812 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs @@ -1,20 +1,44 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using NUnit.Framework; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneSwitchButton : OsuTestScene + public class TestSceneSwitchButton : ManualInputManagerTestScene { - public TestSceneSwitchButton() + private SwitchButton switchButton; + + [SetUp] + public void Setup() => Schedule(() => { - Child = new SwitchButton + Child = switchButton = new SwitchButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, }; + }); + + [Test] + public void TestChangeThroughInput() + { + AddStep("move to switch button", () => InputManager.MoveMouseTo(switchButton)); + AddStep("click on", () => InputManager.Click(MouseButton.Left)); + AddStep("click off", () => InputManager.Click(MouseButton.Left)); + } + + [Test] + public void TestChangeThroughBindable() + { + BindableBool bindable = null; + + AddStep("bind bindable", () => switchButton.Current.BindTo(bindable = new BindableBool())); + AddStep("toggle bindable", () => bindable.Toggle()); + AddStep("toggle bindable", () => bindable.Toggle()); } } } diff --git a/osu.Game/Graphics/UserInterface/SwitchButton.cs b/osu.Game/Graphics/UserInterface/SwitchButton.cs index 21712051ef..9964af91d5 100644 --- a/osu.Game/Graphics/UserInterface/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterface/SwitchButton.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -73,20 +74,20 @@ namespace osu.Game.Graphics.UserInterface switchContainer.Colour = enabledColour; fill.Colour = disabledColour; - - updateBorder(); } - protected override void OnUserChange(bool value) + protected override void LoadComplete() { - base.OnUserChange(value); + base.LoadComplete(); - if (value) - switchCircle.MoveToX(switchContainer.DrawWidth - switchCircle.DrawWidth, 200, Easing.OutQuint); - else - switchCircle.MoveToX(0, 200, Easing.OutQuint); + Current.BindValueChanged(updateState, true); + FinishTransforms(true); + } - fill.FadeTo(value ? 1 : 0, 250, Easing.OutQuint); + private void updateState(ValueChangedEvent state) + { + switchCircle.MoveToX(state.NewValue ? switchContainer.DrawWidth - switchCircle.DrawWidth : 0, 200, Easing.OutQuint); + fill.FadeTo(state.NewValue ? 1 : 0, 250, Easing.OutQuint); updateBorder(); } From c9e39c124e5817bce9909acc8e057606701ea0ce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Sep 2019 17:42:35 +0900 Subject: [PATCH 134/966] Add a labelled switch button --- .../TestSceneLabelledSwitchButton.cs | 50 +++++++++++++++++++ .../LabelledSwitchButton.cs | 17 +++++++ 2 files changed, 67 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs create mode 100644 osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledSwitchButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs new file mode 100644 index 0000000000..dbce08c898 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs @@ -0,0 +1,50 @@ +// 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.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneLabelledSwitchButton : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(LabelledSwitchButton), + typeof(SwitchButton) + }; + + [TestCase(false)] + [TestCase(true)] + public void TestSwitchButton(bool hasDescription) => createSwitchButton(hasDescription); + + private void createSwitchButton(bool hasDescription = false) + { + AddStep("create component", () => + { + LabelledSwitchButton component; + + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 500, + AutoSizeAxes = Axes.Y, + Child = component = new LabelledSwitchButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + + component.Label = "a sample component"; + component.Description = hasDescription ? "this text describes the component" : string.Empty; + }); + } + } +} diff --git a/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledSwitchButton.cs b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledSwitchButton.cs new file mode 100644 index 0000000000..54f6184578 --- /dev/null +++ b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledSwitchButton.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents +{ + public class LabelledSwitchButton : LabelledComponent + { + public LabelledSwitchButton() + : base(true) + { + } + + protected override SwitchButton CreateComponent() => new SwitchButton(); + } +} From 9f77a1ef35c081db6812bbd40e38185101ae4fcc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Sep 2019 17:53:08 +0900 Subject: [PATCH 135/966] Adjust namespaces --- .../Visual/UserInterface/TestSceneLabelledSwitchButton.cs | 3 +-- osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs | 2 +- osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs | 4 +--- .../{UserInterface => UserInterfaceV2}/SwitchButton.cs | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) rename osu.Game/Graphics/{UserInterface => UserInterfaceV2}/SwitchButton.cs (98%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs index dbce08c898..6ca4d9fa4c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs @@ -6,8 +6,7 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Tests.Visual.UserInterface { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs index bf9071b812..4a104b4a41 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs @@ -4,7 +4,7 @@ using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs index 54f6184578..c973f1d13e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs @@ -1,9 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents +namespace osu.Game.Graphics.UserInterfaceV2 { public class LabelledSwitchButton : LabelledComponent { diff --git a/osu.Game/Graphics/UserInterface/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs similarity index 98% rename from osu.Game/Graphics/UserInterface/SwitchButton.cs rename to osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index 9964af91d5..a7fd25b554 100644 --- a/osu.Game/Graphics/UserInterface/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -13,7 +13,7 @@ using osu.Framework.Input.Events; using osuTK; using osuTK.Graphics; -namespace osu.Game.Graphics.UserInterface +namespace osu.Game.Graphics.UserInterfaceV2 { public class SwitchButton : Checkbox { From f11156c2dc644e34f68c883b2b7d9bdf3a63c380 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Sep 2019 19:24:05 +0900 Subject: [PATCH 136/966] Fix tests not working correctly --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 107 +++++++++++++++--- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index ab519360ac..eb54eca0cb 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -7,10 +7,15 @@ using System.Linq; using System.Threading; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; using osu.Framework.Screens; +using osu.Game.Graphics.Containers; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; @@ -18,25 +23,41 @@ using osu.Game.Scoring; using osu.Game.Screens; using osu.Game.Screens.Play; using osu.Game.Screens.Play.PlayerSettings; +using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { public class TestScenePlayerLoader : ManualInputManagerTestScene { private TestPlayerLoader loader; - private OsuScreenStack stack; + private TestPlayerLoaderContainer container; + private TestPlayer player; - [SetUp] - public void Setup() => Schedule(() => + [Resolved] + private AudioManager audioManager { get; set; } + + /// + /// Sets the input manager child to a new test player loader container instance. + /// + /// If the test player should behave like the production one. + /// An action to run before player load but after bindable leases are returned. + public void ResetPlayer(bool interactive, Action beforeLoadAction = null) { - InputManager.Child = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; + audioManager.Volume.SetDefault(); + + InputManager.Clear(); + + beforeLoadAction?.Invoke(); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); - }); + + InputManager.Child = container = new TestPlayerLoaderContainer( + loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive))); + } [Test] public void TestBlockLoadViaMouseMovement() { - AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false)))); + AddStep("load dummy beatmap", () => ResetPlayer(false)); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20); AddAssert("loader still active", () => loader.IsCurrentScreen()); @@ -46,16 +67,17 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestLoadContinuation() { - Player player = null; SlowLoadPlayer slowPlayer = null; - AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer(false, false)))); + AddStep("load dummy beatmap", () => ResetPlayer(false)); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); AddUntilStep("wait for player to be current", () => player.IsCurrentScreen()); AddStep("load slow dummy beatmap", () => { - stack.Push(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + InputManager.Child = container = new TestPlayerLoaderContainer( + loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000); }); @@ -65,16 +87,11 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestModReinstantiation() { - TestPlayer player = null; TestMod gameMod = null; TestMod playerMod1 = null; TestMod playerMod2 = null; - AddStep("load player", () => - { - Mods.Value = new[] { gameMod = new TestMod() }; - stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer())); - }); + AddStep("load player", () => { ResetPlayer(true, () => Mods.Value = new[] { gameMod = new TestMod() }); }); AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen()); AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); @@ -97,6 +114,66 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("player mods applied", () => playerMod2.Applied); } + [Test] + public void TestMutedNotification() + { + AddStep("reset notification", PlayerLoader.ResetNotificationLock); + + AddStep("load player", () => ResetPlayer(false, () => audioManager.Volume.Value = 0)); + AddUntilStep("wait for player", () => player.IsLoaded); + + AddAssert("check for notification", () => container.NotificationOverlay.UnreadCount.Value == 1); + AddStep("click notification", () => + { + var scrollContainer = (OsuScrollContainer)container.NotificationOverlay.Children.Last(); + var flowContainer = scrollContainer.Children.OfType>().First(); + var notification = flowContainer.First(); + + InputManager.MoveMouseTo(notification); + InputManager.Click(MouseButton.Left); + }); + AddAssert("check master volume", () => audioManager.Volume.IsDefault); + + AddStep("restart player", () => + { + var lastPlayer = player; + player = null; + lastPlayer.Restart(); + }); + } + + private class TestPlayerLoaderContainer : Container + { + [Cached] + public readonly NotificationOverlay NotificationOverlay; + + [Cached] + public readonly VolumeOverlay VolumeOverlay; + + public TestPlayerLoaderContainer(IScreen screen) + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new OsuScreenStack(screen) + { + RelativeSizeAxes = Axes.Both, + }, + NotificationOverlay = new NotificationOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }, + VolumeOverlay = new VolumeOverlay + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + } + }; + } + } + private class TestPlayerLoader : PlayerLoader { public new VisualSettings VisualSettings => base.VisualSettings; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 8f2435d2f7..053e11104f 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -530,7 +530,7 @@ namespace osu.Game.Screens.Play } /// - /// Sets to , reserved for testing. + /// Sets to false, reserved for testing. /// public static void ResetNotificationLock() { From ccb56234877e204009e97e58de868b6a8710b155 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Sep 2019 20:03:03 +0900 Subject: [PATCH 137/966] Fix test name --- .../Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index 86f7896457..c3b61fa420 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestSliderMultiplierDoesnotAffectRelativeBeatLength() + public void TestSliderMultiplierDoesNotAffectRelativeBeatLength() { var beatmap = createBeatmap(new TimingControlPoint { BeatLength = time_range }); beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2; From 244627ff10cb1b517634a0278fa26eb27a000d3c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Sep 2019 20:12:01 +0900 Subject: [PATCH 138/966] Add comment + test for slider multiplier --- .../Gameplay/TestSceneDrawableScrollingRuleset.cs | 13 +++++++++++++ .../UI/Scrolling/DrawableScrollingRuleset.cs | 2 ++ 2 files changed, 15 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index c3b61fa420..dcab964d6d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -129,6 +129,19 @@ namespace osu.Game.Tests.Visual.Gameplay assertPosition(i, i / 5f); } + [Test] + public void TestSliderMultiplierAffectsNonRelativeBeatLength() + { + var beatmap = createBeatmap(new TimingControlPoint { BeatLength = time_range }); + beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2; + + createTest(beatmap); + AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 2000); + + assertPosition(0, 0); + assertPosition(1, 1); + } + private void assertPosition(int index, float relativeY) => AddAssert($"hitobject {index} at {relativeY}", () => Precision.AlmostEquals(drawableRuleset.Playfield.AllHitObjects.ElementAt(index).DrawPosition.Y, drawableRuleset.Playfield.HitObjectContainer.DrawHeight * relativeY)); diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 3d56543bab..f178c01fd6 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -131,6 +131,8 @@ namespace osu.Game.Rulesets.UI.Scrolling if (duration > maxDuration) { maxDuration = duration; + // The slider multiplier is post-multiplied to determine the final velocity, but for relative scale beat lengths + // the multiplier should not affect the effective timing point (the longest in the beatmap), so it is factored out here baseBeatLength = timingPoints[i].BeatLength / Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier; } } From 8844d567cb1220dfe1b261ff30108dea5ae1c527 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 25 Sep 2019 15:56:47 +0300 Subject: [PATCH 139/966] Use bindable setting instead --- osu.Game/Screens/Menu/MainMenu.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 98ceb315a2..004bba20d4 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -52,9 +52,6 @@ namespace osu.Game.Screens.Menu [Resolved(canBeNull: true)] private LoginOverlay login { get; set; } - [Resolved] - private SessionStatics statics { get; set; } - [Resolved] private IAPIProvider api { get; set; } @@ -66,13 +63,15 @@ namespace osu.Game.Screens.Menu protected override BackgroundScreen CreateBackground() => background; private Bindable holdDelay; + private Bindable loginDisplayed; private ExitConfirmOverlay exitConfirmOverlay; [BackgroundDependencyLoader(true)] - private void load(DirectOverlay direct, SettingsOverlay settings, OsuConfigManager config) + private void load(DirectOverlay direct, SettingsOverlay settings, OsuConfigManager config, SessionStatics statics) { holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + loginDisplayed = statics.GetBindable(Statics.LoginOverlayDisplayed); if (host.CanExit) { @@ -200,10 +199,10 @@ namespace osu.Game.Screens.Menu bool displayLogin() { - if (!statics.Get(Statics.LoginOverlayDisplayed)) + if (!loginDisplayed.Value) { Scheduler.AddDelayed(() => login?.Show(), 500); - statics.Set(Statics.LoginOverlayDisplayed, true); + loginDisplayed.Value = true; } return true; From 42fd323020f3df9f16be166a91935e6ffb046302 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Sep 2019 22:13:49 +0900 Subject: [PATCH 140/966] Move protected method --- osu.Game/OsuGame.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index aaaa320093..3a7e53905c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -106,8 +106,6 @@ namespace osu.Game private readonly List visibleBlockingOverlays = new List(); - protected virtual Loader CreateLoader() => new Loader(); - public OsuGame(string[] args = null) { this.args = args; @@ -322,6 +320,8 @@ namespace osu.Game }, $"watch {databasedScoreInfo}", bypassScreenAllowChecks: true); } + protected virtual Loader CreateLoader() => new Loader(); + #region Beatmap progression private void beatmapChanged(ValueChangedEvent beatmap) From 45f833ceea17628cc54856bb9aa58916e0dc6589 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Sep 2019 22:14:42 +0900 Subject: [PATCH 141/966] Add invocation null checks for safety --- osu.Game/Graphics/UserInterface/BackButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index 5fa634425b..62c33b9a39 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface public BackButton(Receptor receptor) { - receptor.OnBackPressed = () => Action.Invoke(); + receptor.OnBackPressed = () => Action?.Invoke(); Size = TwoLayerButton.SIZE_EXTENDED; @@ -60,7 +60,7 @@ namespace osu.Game.Graphics.UserInterface switch (action) { case GlobalAction.Back: - OnBackPressed.Invoke(); + OnBackPressed?.Invoke(); return true; } From 911094e79049a244a68912c01e717015689c8ff0 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 26 Sep 2019 01:42:56 +0300 Subject: [PATCH 142/966] Replace menu button text with "press for menu" on 0ms activation delay --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 91c14591b1..6b2bbc13b7 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.MathUtils; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -45,7 +46,6 @@ namespace osu.Game.Screens.Play.HUD { text = new OsuSpriteText { - Text = "hold for menu", Font = OsuFont.GetFont(weight: FontWeight.Bold), Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft @@ -60,6 +60,14 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both; } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + text.Text = config.Get(OsuSetting.UIHoldActivationDelay) > 0 + ? "hold for menu" + : "press for menu"; + } + protected override void LoadComplete() { text.FadeInFromZero(500, Easing.OutQuint).Delay(1500).FadeOut(500, Easing.OutQuint); From 186ea9821708da3260601fc9f6c9ba08ad4e49be Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 26 Sep 2019 02:23:18 +0300 Subject: [PATCH 143/966] Wait for track to start running instead --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index 7e792f0b40..cd46bc63a9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -41,10 +41,8 @@ namespace osu.Game.Rulesets.Osu.Tests { base.SetUpSteps(); + AddUntilStep("wait for track to start running", () => track.IsRunning); AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.First()); - - // wait for frame stable clock time to hit 0 (for some reason, executing a seek while current time is below 0 doesn't seek successfully) - addSeekStep(0); } [Test] From d773f0cce18b7bad01bebd4f593504ae670658cb Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 26 Sep 2019 04:38:20 +0300 Subject: [PATCH 144/966] Override autoplay bool instead of adding it --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index cd46bc63a9..4eb4c21c90 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -27,6 +27,8 @@ namespace osu.Game.Rulesets.Osu.Tests private TrackVirtualManual track; + protected override bool Autoplay => true; + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) { var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); @@ -75,12 +77,6 @@ namespace osu.Game.Rulesets.Osu.Tests AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, ((TestPlayer)Player).DrawableRuleset.FrameStableClock.CurrentTime, 100)); } - protected override Player CreatePlayer(Ruleset ruleset) - { - Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray(); - return new TestPlayer(); - } - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap { HitObjects = new List From c57868795e08063241810b497ccc072d78972513 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 26 Sep 2019 04:38:57 +0300 Subject: [PATCH 145/966] Remove redundant using directive --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index 4eb4c21c90..cded7f0e95 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -11,7 +11,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Screens.Play; using osu.Game.Tests.Visual; using osuTK; using System.Collections.Generic; From bbf0544a8d0f476eb969aec5852042b286730e94 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Sep 2019 16:55:08 +0900 Subject: [PATCH 146/966] Add bindables for IHasComboInformation properties --- .../Objects/CatchHitObject.cs | 25 +++++++++++++-- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 32 ++++++++++++++++--- .../Objects/Types/IHasComboInformation.cs | 8 +++++ 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index a25d9cb67e..77d7de989a 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -1,6 +1,7 @@ // 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.Bindables; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Catch.Beatmaps; @@ -37,9 +38,21 @@ namespace osu.Game.Rulesets.Catch.Objects public int ComboOffset { get; set; } - public int IndexInCurrentCombo { get; set; } + public Bindable IndexInCurrentComboBindable { get; } = new Bindable(); - public int ComboIndex { get; set; } + public int IndexInCurrentCombo + { + get => IndexInCurrentComboBindable.Value; + set => IndexInCurrentComboBindable.Value = value; + } + + public Bindable ComboIndexBindable { get; } = new Bindable(); + + public int ComboIndex + { + get => ComboIndexBindable.Value; + set => ComboIndexBindable.Value = value; + } /// /// Difference between the distance to the next object @@ -48,10 +61,16 @@ namespace osu.Game.Rulesets.Catch.Objects /// public float DistanceToHyperDash { get; set; } + public Bindable LastInComboBindable { get; } = new Bindable(); + /// /// The next fruit starts a new combo. Used for explodey. /// - public virtual bool LastInCombo { get; set; } + public virtual bool LastInCombo + { + get => LastInComboBindable.Value; + set => LastInComboBindable.Value = value; + } public float Scale { get; set; } = 1; diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 2cf877b000..80e013fe68 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -58,13 +58,37 @@ namespace osu.Game.Rulesets.Osu.Objects public virtual bool NewCombo { get; set; } - public int ComboOffset { get; set; } + public readonly Bindable ComboOffsetBindable = new Bindable(); - public virtual int IndexInCurrentCombo { get; set; } + public int ComboOffset + { + get => ComboOffsetBindable.Value; + set => ComboOffsetBindable.Value = value; + } - public virtual int ComboIndex { get; set; } + public Bindable IndexInCurrentComboBindable { get; } = new Bindable(); - public bool LastInCombo { get; set; } + public virtual int IndexInCurrentCombo + { + get => IndexInCurrentComboBindable.Value; + set => IndexInCurrentComboBindable.Value = value; + } + + public Bindable ComboIndexBindable { get; } = new Bindable(); + + public virtual int ComboIndex + { + get => ComboIndexBindable.Value; + set => ComboIndexBindable.Value = value; + } + + public Bindable LastInComboBindable { get; } = new Bindable(); + + public bool LastInCombo + { + get => LastInComboBindable.Value; + set => LastInComboBindable.Value = value; + } protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { diff --git a/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs b/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs index e07da93a3a..4e3de04278 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs @@ -1,6 +1,8 @@ // 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.Bindables; + namespace osu.Game.Rulesets.Objects.Types { /// @@ -8,16 +10,22 @@ namespace osu.Game.Rulesets.Objects.Types /// public interface IHasComboInformation : IHasCombo { + Bindable IndexInCurrentComboBindable { get; } + /// /// The offset of this hitobject in the current combo. /// int IndexInCurrentCombo { get; set; } + Bindable ComboIndexBindable { get; } + /// /// The offset of this combo in relation to the beatmap. /// int ComboIndex { get; set; } + Bindable LastInComboBindable { get; } + /// /// Whether this is the last object in the current combo. /// From 3155a9050119ecb1edf3aad8fa6518fe2cd104fa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Sep 2019 16:57:58 +0900 Subject: [PATCH 147/966] Use bindables for displayed circle piece numbers --- .../Objects/Drawables/DrawableHitCircle.cs | 2 +- .../Objects/Drawables/Pieces/MainCirclePiece.cs | 16 +++++++++------- .../Skinning/LegacyMainCirclePiece.cs | 16 +++++++++------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index c90f230f93..bb227d76df 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return true; }, }, - CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), + CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece()), ApproachCircle = new ApproachCircle { Alpha = 0, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs index 944c93bb6d..e364c96426 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private readonly NumberPiece number; private readonly GlowPiece glow; - public MainCirclePiece(int index) + public MainCirclePiece() { Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); @@ -31,10 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { glow = new GlowPiece(), circle = new CirclePiece(), - number = new NumberPiece - { - Text = (index + 1).ToString(), - }, + number = new NumberPiece(), ring = new RingPiece(), flash = new FlashPiece(), explode = new ExplodePiece(), @@ -42,12 +39,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } private readonly IBindable state = new Bindable(); - - private readonly Bindable accentColour = new Bindable(); + private readonly IBindable accentColour = new Bindable(); + private readonly IBindable indexInCurrentCombo = new Bindable(); [BackgroundDependencyLoader] private void load(DrawableHitObject drawableObject) { + OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject; + state.BindTo(drawableObject.State); state.BindValueChanged(updateState, true); @@ -58,6 +57,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces glow.Colour = colour.NewValue; circle.Colour = colour.NewValue; }, true); + + indexInCurrentCombo.BindTo(osuObject.IndexInCurrentComboBindable); + indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); } private void updateState(ValueChangedEvent state) diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs index 83d507f64b..93ae0371df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Skinning; using osuTK; @@ -25,13 +24,16 @@ namespace osu.Game.Rulesets.Osu.Skinning } private readonly IBindable state = new Bindable(); - private readonly Bindable accentColour = new Bindable(); + private readonly IBindable indexInCurrentCombo = new Bindable(); [BackgroundDependencyLoader] private void load(DrawableHitObject drawableObject, ISkinSource skin) { + OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject; + Sprite hitCircleSprite; + SkinnableSpriteText hitCircleText; InternalChildren = new Drawable[] { @@ -42,14 +44,11 @@ namespace osu.Game.Rulesets.Osu.Skinning Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText + hitCircleText = new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, - }, confineMode: ConfineMode.NoScaling) - { - Text = (((IHasComboInformation)drawableObject.HitObject).IndexInCurrentCombo + 1).ToString() - }, + }, confineMode: ConfineMode.NoScaling), new Sprite { Texture = skin.GetTexture("hitcircleoverlay"), @@ -63,6 +62,9 @@ namespace osu.Game.Rulesets.Osu.Skinning accentColour.BindTo(drawableObject.AccentColour); accentColour.BindValueChanged(colour => hitCircleSprite.Colour = colour.NewValue, true); + + indexInCurrentCombo.BindTo(osuObject.IndexInCurrentComboBindable); + indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); } private void updateState(ValueChangedEvent state) From 706e884cc05cdd04cb4e56cb3e1f0c9f583e1d0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Sep 2019 17:04:38 +0900 Subject: [PATCH 148/966] Update accent colour on combo index change --- .../Objects/Drawables/DrawableHitObject.cs | 25 ++++++++++++++----- osu.Game/Skinning/SkinReloadableDrawable.cs | 20 +++++++++------ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 8d8f8a419f..f8bc74b2a6 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -76,6 +76,8 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public JudgementResult Result { get; private set; } + private Bindable comboIndexBindable; + public override bool RemoveWhenNotAlive => false; public override bool RemoveCompletedTransforms => false; protected override bool RequiresChildrenUpdate => true; @@ -122,6 +124,13 @@ namespace osu.Game.Rulesets.Objects.Drawables protected override void LoadComplete() { base.LoadComplete(); + + if (HitObject is IHasComboInformation combo) + { + comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy(); + comboIndexBindable.BindValueChanged(_ => updateAccentColour()); + } + updateState(ArmedState.Idle, true); } @@ -244,12 +253,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { base.SkinChanged(skin, allowFallback); - if (HitObject is IHasComboInformation combo) - { - var comboColours = skin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value; - - AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; - } + updateAccentColour(); ApplySkin(skin, allowFallback); @@ -257,6 +261,15 @@ namespace osu.Game.Rulesets.Objects.Drawables updateState(State.Value, true); } + private void updateAccentColour() + { + if (HitObject is IHasComboInformation combo) + { + var comboColours = CurrentSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value; + AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; + } + } + /// /// Called when a change is made to the skin. /// diff --git a/osu.Game/Skinning/SkinReloadableDrawable.cs b/osu.Game/Skinning/SkinReloadableDrawable.cs index 4bbdeafba5..6d0b22dd51 100644 --- a/osu.Game/Skinning/SkinReloadableDrawable.cs +++ b/osu.Game/Skinning/SkinReloadableDrawable.cs @@ -12,13 +12,17 @@ namespace osu.Game.Skinning /// public abstract class SkinReloadableDrawable : CompositeDrawable { + /// + /// The current skin source. + /// + protected ISkinSource CurrentSkin { get; private set; } + private readonly Func allowFallback; - private ISkinSource skin; /// /// Whether fallback to default skin should be allowed if the custom skin is missing this resource. /// - private bool allowDefaultFallback => allowFallback == null || allowFallback.Invoke(skin); + private bool allowDefaultFallback => allowFallback == null || allowFallback.Invoke(CurrentSkin); /// /// Create a new @@ -32,19 +36,19 @@ namespace osu.Game.Skinning [BackgroundDependencyLoader] private void load(ISkinSource source) { - skin = source; - skin.SourceChanged += onChange; + CurrentSkin = source; + CurrentSkin.SourceChanged += onChange; } private void onChange() => // schedule required to avoid calls after disposed. // note that this has the side-effect of components only performing a skin change when they are alive. - Scheduler.AddOnce(() => SkinChanged(skin, allowDefaultFallback)); + Scheduler.AddOnce(() => SkinChanged(CurrentSkin, allowDefaultFallback)); protected override void LoadAsyncComplete() { base.LoadAsyncComplete(); - SkinChanged(skin, allowDefaultFallback); + SkinChanged(CurrentSkin, allowDefaultFallback); } /// @@ -60,8 +64,8 @@ namespace osu.Game.Skinning { base.Dispose(isDisposing); - if (skin != null) - skin.SourceChanged -= onChange; + if (CurrentSkin != null) + CurrentSkin.SourceChanged -= onChange; } } } From ea76dd6a9e1adde6941005ffb6114bcceced2a52 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Sep 2019 17:18:16 +0900 Subject: [PATCH 149/966] Add test scene for hitcircles and combo changes --- .../TestSceneHitCircleComboChange.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs new file mode 100644 index 0000000000..5695462859 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs @@ -0,0 +1,26 @@ +// 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.Bindables; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneHitCircleComboChange : TestSceneHitCircle + { + private readonly Bindable comboIndex = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + Scheduler.AddDelayed(() => comboIndex.Value++, 250, true); + } + + protected override TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto) + { + circle.ComboIndexBindable.BindTo(comboIndex); + circle.IndexInCurrentComboBindable.BindTo(comboIndex); + return base.CreateDrawableHitCircle(circle, auto); + } + } +} From 45f2bcc440c4aea51f0905b4da7f1128dcc415f3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Sep 2019 17:39:19 +0900 Subject: [PATCH 150/966] Fix combo bindings not being bound to nested hitobjects --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 26 ------------------------- osu.Game/Beatmaps/BeatmapProcessor.cs | 20 ------------------- osu.Game/Rulesets/Objects/HitObject.cs | 10 ++++++++++ 3 files changed, 10 insertions(+), 46 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 2805494021..d8514092bc 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -33,28 +33,6 @@ namespace osu.Game.Rulesets.Osu.Objects public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t); - public override int ComboIndex - { - get => base.ComboIndex; - set - { - base.ComboIndex = value; - foreach (var n in NestedHitObjects.OfType()) - n.ComboIndex = value; - } - } - - public override int IndexInCurrentCombo - { - get => base.IndexInCurrentCombo; - set - { - base.IndexInCurrentCombo = value; - foreach (var n in NestedHitObjects.OfType()) - n.IndexInCurrentCombo = value; - } - } - public readonly Bindable PathBindable = new Bindable(); public SliderPath Path @@ -192,8 +170,6 @@ namespace osu.Game.Rulesets.Osu.Objects Position = Position, Samples = getNodeSamples(0), SampleControlPoint = SampleControlPoint, - IndexInCurrentCombo = IndexInCurrentCombo, - ComboIndex = ComboIndex, }); break; @@ -205,8 +181,6 @@ namespace osu.Game.Rulesets.Osu.Objects { StartTime = e.Time, Position = EndPosition, - IndexInCurrentCombo = IndexInCurrentCombo, - ComboIndex = ComboIndex, }); break; diff --git a/osu.Game/Beatmaps/BeatmapProcessor.cs b/osu.Game/Beatmaps/BeatmapProcessor.cs index 7a612893c9..250cc49ad4 100644 --- a/osu.Game/Beatmaps/BeatmapProcessor.cs +++ b/osu.Game/Beatmaps/BeatmapProcessor.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Beatmaps @@ -45,25 +44,6 @@ namespace osu.Game.Beatmaps public virtual void PostProcess() { - void updateNestedCombo(HitObject obj, int comboIndex, int indexInCurrentCombo) - { - if (obj is IHasComboInformation objectComboInfo) - { - objectComboInfo.ComboIndex = comboIndex; - objectComboInfo.IndexInCurrentCombo = indexInCurrentCombo; - foreach (var nestedObject in obj.NestedHitObjects) - updateNestedCombo(nestedObject, comboIndex, indexInCurrentCombo); - } - } - - foreach (var hitObject in Beatmap.HitObjects) - { - if (hitObject is IHasComboInformation objectComboInfo) - { - foreach (var nested in hitObject.NestedHitObjects) - updateNestedCombo(nested, objectComboInfo.ComboIndex, objectComboInfo.IndexInCurrentCombo); - } - } } } } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 96297ab44f..6c5627c5d2 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using Newtonsoft.Json; using osu.Game.Audio; @@ -82,6 +83,15 @@ namespace osu.Game.Rulesets.Objects CreateNestedHitObjects(); + if (this is IHasComboInformation hasCombo) + { + foreach (var n in NestedHitObjects.OfType()) + { + n.ComboIndexBindable.BindTo(hasCombo.ComboIndexBindable); + n.IndexInCurrentComboBindable.BindTo(hasCombo.IndexInCurrentComboBindable); + } + } + nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); foreach (var h in nestedHitObjects) From e4e66344322dc9733b61e464712541c4ac1b51fe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Sep 2019 17:39:26 +0900 Subject: [PATCH 151/966] Add slider combo change test --- .../TestSceneSlider.cs | 12 ++++---- .../TestSceneSliderComboChange.cs | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs index 29c71a8903..6a4201f84d 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs @@ -297,11 +297,7 @@ namespace osu.Game.Rulesets.Osu.Tests slider.ApplyDefaults(cpi, new BeatmapDifficulty { CircleSize = circleSize, SliderTickRate = 3 }); - var drawable = new DrawableSlider(slider) - { - Anchor = Anchor.Centre, - Depth = depthIndex++ - }; + var drawable = CreateDrawableSlider(slider); foreach (var mod in Mods.Value.OfType()) mod.ApplyToDrawableHitObjects(new[] { drawable }); @@ -311,6 +307,12 @@ namespace osu.Game.Rulesets.Osu.Tests return drawable; } + protected virtual DrawableSlider CreateDrawableSlider(Slider slider) => new DrawableSlider(slider) + { + Anchor = Anchor.Centre, + Depth = depthIndex++ + }; + private float judgementOffsetDirection = 1; private void onNewResult(DrawableHitObject judgedObject, JudgementResult result) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs new file mode 100644 index 0000000000..13ced3019e --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs @@ -0,0 +1,28 @@ +// 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.Bindables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneSliderComboChange : TestSceneSlider + { + private readonly Bindable comboIndex = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + Scheduler.AddDelayed(() => comboIndex.Value++, 250, true); + } + + protected override DrawableSlider CreateDrawableSlider(Slider slider) + { + slider.ComboIndexBindable.BindTo(comboIndex); + slider.IndexInCurrentComboBindable.BindTo(comboIndex); + + return base.CreateDrawableSlider(slider); + } + } +} From 9a31ccd2e34bc56960e714db87bda72c5fb6282a Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 26 Sep 2019 14:05:43 +0200 Subject: [PATCH 152/966] Add missing test cases for master, track and mute button This also modifies the reset player method to make it possible to set something before the player is loaded but after the container has loaded. --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index eb54eca0cb..e1a2cdcca3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -41,7 +41,8 @@ namespace osu.Game.Tests.Visual.Gameplay /// /// If the test player should behave like the production one. /// An action to run before player load but after bindable leases are returned. - public void ResetPlayer(bool interactive, Action beforeLoadAction = null) + /// An action to run after container load. + public void ResetPlayer(bool interactive, Action beforeLoadAction = null, Action afterLoadAction = null) { audioManager.Volume.SetDefault(); @@ -51,7 +52,11 @@ namespace osu.Game.Tests.Visual.Gameplay Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); InputManager.Child = container = new TestPlayerLoaderContainer( - loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive))); + loader = new TestPlayerLoader(() => + { + afterLoadAction?.Invoke(); + return player = new TestPlayer(interactive, interactive); + })); } [Test] @@ -115,11 +120,26 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestMutedNotification() - { - AddStep("reset notification", PlayerLoader.ResetNotificationLock); + public void TestMutedNotificationMasterVolume() => addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault); - AddStep("load player", () => ResetPlayer(false, () => audioManager.Volume.Value = 0)); + [Test] + public void TestMutedNotificationTrackVolume() => addVolumeSteps("music volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault); + + [Test] + public void TestMutedNotificationMuteButton() => addVolumeSteps("mute button", null, () => container.VolumeOverlay.IsMuted.Value = true, () => !container.VolumeOverlay.IsMuted.Value); + + /// + /// Created for avoiding copy pasting code for the same steps. + /// + /// What part of the volume system is checked + /// The action to be invoked to set the volume before loading + /// The action to be invoked to set the volume after loading + /// The function to be invoked and checked + private void addVolumeSteps(string volumeName, Action beforeLoad, Action afterLoad, Func assert) + { + AddStep("reset notification lock", PlayerLoader.ResetNotificationLock); + + AddStep("load player", () => ResetPlayer(false, beforeLoad, afterLoad)); AddUntilStep("wait for player", () => player.IsLoaded); AddAssert("check for notification", () => container.NotificationOverlay.UnreadCount.Value == 1); @@ -132,14 +152,8 @@ namespace osu.Game.Tests.Visual.Gameplay InputManager.MoveMouseTo(notification); InputManager.Click(MouseButton.Left); }); - AddAssert("check master volume", () => audioManager.Volume.IsDefault); - AddStep("restart player", () => - { - var lastPlayer = player; - player = null; - lastPlayer.Restart(); - }); + AddAssert("check " + volumeName, assert); } private class TestPlayerLoaderContainer : Container From 7904f77cd5cd716c6547b3ee8a7dea2bd79ce5df Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 27 Sep 2019 02:59:42 +0300 Subject: [PATCH 153/966] Bind event to activation delay change --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 6b2bbc13b7..9c1435ef3d 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -63,9 +63,13 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - text.Text = config.Get(OsuSetting.UIHoldActivationDelay) > 0 - ? "hold for menu" - : "press for menu"; + var activationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay).GetBoundCopy(); + activationDelay.BindValueChanged(v => + { + text.Text = v.NewValue > 0 + ? "hold for menu" + : "press for menu"; + }, true); } protected override void LoadComplete() From 2670a23e6f313875aeb0301d7cd6fc67b7c253ea Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 27 Sep 2019 08:15:24 +0300 Subject: [PATCH 154/966] Assign to field and move to load complete --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 9c1435ef3d..2dc50326a8 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -60,21 +60,23 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both; } - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + [Resolved] + private OsuConfigManager config { get; set; } + + private Bindable activationDelay; + + protected override void LoadComplete() { - var activationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay).GetBoundCopy(); + activationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); activationDelay.BindValueChanged(v => { text.Text = v.NewValue > 0 ? "hold for menu" : "press for menu"; }, true); - } - protected override void LoadComplete() - { text.FadeInFromZero(500, Easing.OutQuint).Delay(1500).FadeOut(500, Easing.OutQuint); + base.LoadComplete(); } From b50ef8ffa4855cecb9ae195accd455669b279feb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Sep 2019 13:15:33 +0800 Subject: [PATCH 155/966] Allow null NotificationManager --- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 053e11104f..6cde7522d4 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Play private IdleTracker idleTracker; - [Resolved] + [Resolved(CanBeNull = true)] private NotificationOverlay notificationOverlay { get; set; } [Resolved] @@ -164,7 +164,7 @@ namespace osu.Game.Screens.Play //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. if (!muteWarningShownOnce && (volumeOverlay.IsMuted.Value || audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue)) { - notificationOverlay.Post(new MutedNotification()); + notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce = true; } } From f4f5a7e9c8be2b2d0f48a9b5be9a8761d4b856b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Sep 2019 13:20:17 +0800 Subject: [PATCH 156/966] Fix test regressions --- osu.Game/Screens/Play/PlayerLoader.cs | 32 +++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6cde7522d4..157ff8fcd4 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -59,17 +59,6 @@ namespace osu.Game.Screens.Play private IdleTracker idleTracker; - [Resolved(CanBeNull = true)] - private NotificationOverlay notificationOverlay { get; set; } - - [Resolved] - private VolumeOverlay volumeOverlay { get; set; } - - [Resolved] - private AudioManager audioManager { get; set; } - - private static bool muteWarningShownOnce; - public PlayerLoader(Func createPlayer) { this.createPlayer = createPlayer; @@ -159,10 +148,24 @@ namespace osu.Game.Screens.Play content.FadeOut(250); } - private void checkVolume(AudioManager audio) + [Resolved(CanBeNull = true)] + private NotificationOverlay notificationOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private VolumeOverlay volumeOverlay { get; set; } + + [Resolved] + private AudioManager audioManager { get; set; } + + private static bool muteWarningShownOnce; + + private void checkVolume() { + if (muteWarningShownOnce) + return; + //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (!muteWarningShownOnce && (volumeOverlay.IsMuted.Value || audio.Volume.Value <= audio.Volume.MinValue || audio.VolumeTrack.Value <= audio.VolumeTrack.MinValue)) + if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) { notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce = true; @@ -213,7 +216,8 @@ namespace osu.Game.Screens.Play { inputManager = GetContainingInputManager(); base.LoadComplete(); - checkVolume(audioManager); + + checkVolume(); } private ScheduledDelegate pushDebounce; From 67bed57cbdf3f0921a6a721c74cc28317afc74c7 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 27 Sep 2019 08:46:49 +0300 Subject: [PATCH 157/966] Bind value changed event of cursor trail appearence outside BDL https://github.com/ppy/osu/pull/6270#discussion_r328899728 --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index a944ff88c6..6dbdf0114d 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -40,6 +40,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private void load(OsuRulesetConfigManager config) { config?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail); + } + + protected override void LoadComplete() + { + base.LoadComplete(); showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true); } From 94eacbca5dde273bec3a0f2073af9e0ce5cb3097 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 27 Sep 2019 09:22:25 +0300 Subject: [PATCH 158/966] Fix Bot users have all the profile sections in ProfileOverlay --- osu.Game/Overlays/UserProfileOverlay.cs | 5 ++++- osu.Game/Users/User.cs | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index b924b3302f..bc16711ea8 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -44,7 +44,7 @@ namespace osu.Game.Overlays Clear(); lastSection = null; - sections = new ProfileSection[] + sections = !user.IsBot ? new ProfileSection[] { //new AboutSection(), new RecentSection(), @@ -53,6 +53,9 @@ namespace osu.Game.Overlays new HistoricalSection(), new BeatmapsSection(), new KudosuSection() + } : new ProfileSection[] + { + //new AboutSection(), }; tabs = new ProfileTabControl diff --git a/osu.Game/Users/User.cs b/osu.Game/Users/User.cs index 9986f70557..1cb395fd75 100644 --- a/osu.Game/Users/User.cs +++ b/osu.Game/Users/User.cs @@ -78,6 +78,9 @@ namespace osu.Game.Users [JsonProperty(@"is_bng")] public bool IsBNG; + [JsonProperty(@"is_bot")] + public bool IsBot; + [JsonProperty(@"is_active")] public bool Active; From 475455d7cd5f02275ceeed31e34baf63a9bc465a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 27 Sep 2019 09:32:46 +0300 Subject: [PATCH 159/966] Add missing line breaks --- osu.Game/Overlays/UserProfileOverlay.cs | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index bc16711ea8..57b9b6c965 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -44,19 +44,21 @@ namespace osu.Game.Overlays Clear(); lastSection = null; - sections = !user.IsBot ? new ProfileSection[] - { - //new AboutSection(), - new RecentSection(), - new RanksSection(), - //new MedalsSection(), - new HistoricalSection(), - new BeatmapsSection(), - new KudosuSection() - } : new ProfileSection[] - { - //new AboutSection(), - }; + sections = !user.IsBot ? + new ProfileSection[] + { + //new AboutSection(), + new RecentSection(), + new RanksSection(), + //new MedalsSection(), + new HistoricalSection(), + new BeatmapsSection(), + new KudosuSection() + } : + new ProfileSection[] + { + //new AboutSection(), + }; tabs = new ProfileTabControl { From 4908cb826b78d964025708865cc695adb7202a4e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 27 Sep 2019 09:46:11 +0300 Subject: [PATCH 160/966] Fix line breaks --- osu.Game/Overlays/UserProfileOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 57b9b6c965..468eb22b01 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -44,8 +44,8 @@ namespace osu.Game.Overlays Clear(); lastSection = null; - sections = !user.IsBot ? - new ProfileSection[] + sections = !user.IsBot + ? new ProfileSection[] { //new AboutSection(), new RecentSection(), @@ -54,8 +54,8 @@ namespace osu.Game.Overlays new HistoricalSection(), new BeatmapsSection(), new KudosuSection() - } : - new ProfileSection[] + } + : new ProfileSection[] { //new AboutSection(), }; From 06c32d52dca8e465d34546af08505f234f7183a5 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Fri, 27 Sep 2019 09:19:39 +0200 Subject: [PATCH 161/966] Change wrong volume bindable used in test --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index e1a2cdcca3..6866fd4c62 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestMutedNotificationMasterVolume() => addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault); [Test] - public void TestMutedNotificationTrackVolume() => addVolumeSteps("music volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault); + public void TestMutedNotificationTrackVolume() => addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, null, () => audioManager.VolumeTrack.IsDefault); [Test] public void TestMutedNotificationMuteButton() => addVolumeSteps("mute button", null, () => container.VolumeOverlay.IsMuted.Value = true, () => !container.VolumeOverlay.IsMuted.Value); From f64fe22f3669cd2117a295d490ecd6a9f14b8f0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 27 Sep 2019 18:00:24 +0900 Subject: [PATCH 162/966] Remove bindables from osu! selection blueprints --- .../HitCircles/Components/HitCirclePiece.cs | 10 +++++++--- .../Edit/Blueprints/HitObjectPiece.cs | 19 ++----------------- .../Edit/Blueprints/SliderPiece.cs | 17 +++-------------- .../Components/PathControlPointVisualiser.cs | 9 ++------- .../Sliders/Components/SliderBodyPiece.cs | 6 +++--- .../Sliders/Components/SliderCirclePiece.cs | 12 ------------ .../Spinners/Components/SpinnerPiece.cs | 12 +++++++----- 7 files changed, 24 insertions(+), 61 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index fe11ead94d..99928cdad9 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -31,10 +31,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components private void load(OsuColour colours) { Colour = colours.Yellow; + } - PositionBindable.BindValueChanged(_ => UpdatePosition(), true); - StackHeightBindable.BindValueChanged(_ => UpdatePosition()); - ScaleBindable.BindValueChanged(scale => Scale = new Vector2(scale.NewValue), true); + protected override void Update() + { + base.Update(); + + UpdatePosition(); + Scale = new Vector2(hitCircle.Scale); } protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs index 315a5a2b9d..3d7d609c6b 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs @@ -1,11 +1,8 @@ // 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.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; -using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { @@ -14,23 +11,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints /// public abstract class HitObjectPiece : CompositeDrawable { - protected readonly IBindable PositionBindable = new Bindable(); - protected readonly IBindable StackHeightBindable = new Bindable(); - protected readonly IBindable ScaleBindable = new Bindable(); - - private readonly OsuHitObject hitObject; + protected readonly OsuHitObject HitObject; protected HitObjectPiece(OsuHitObject hitObject) { - this.hitObject = hitObject; - } - - [BackgroundDependencyLoader] - private void load() - { - PositionBindable.BindTo(hitObject.PositionBindable); - StackHeightBindable.BindTo(hitObject.StackHeightBindable); - ScaleBindable.BindTo(hitObject.ScaleBindable); + HitObject = hitObject; } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs index 8fd1d6d6f9..e0fcf8a000 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs @@ -1,32 +1,21 @@ // 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.Allocation; -using osu.Framework.Bindables; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { /// - /// A piece of a blueprint which responds to changes in the state of a . + /// A piece of a blueprint which responds to changes in the state of a . /// public abstract class SliderPiece : HitObjectPiece { - protected readonly IBindable PathBindable = new Bindable(); - - private readonly Slider slider; + protected readonly Slider Slider; protected SliderPiece(Slider slider) : base(slider) { - this.slider = slider; - } - - [BackgroundDependencyLoader] - private void load() - { - PathBindable.BindTo(slider.PathBindable); + Slider = slider; } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index df846b5d5b..3d8e014551 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.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.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; @@ -22,14 +21,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; } - [BackgroundDependencyLoader] - private void load() + protected override void Update() { - PathBindable.BindValueChanged(_ => updatePathControlPoints(), true); - } + base.Update(); - private void updatePathControlPoints() - { while (slider.Path.ControlPoints.Length > pieces.Count) pieces.Add(new PathControlPointPiece(slider, pieces.Count)); while (slider.Path.ControlPoints.Length < pieces.Count) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index f1f55731b6..aea17a4b8f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -31,9 +31,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private void load(OsuColour colours) { body.BorderColour = colours.Yellow; - - PositionBindable.BindValueChanged(_ => updatePosition(), true); - ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * OsuHitObject.OBJECT_RADIUS, true); } private void updatePosition() => Position = slider.StackedPosition; @@ -42,6 +39,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.Update(); + Position = slider.StackedPosition; + body.PathRadius = HitObject.Scale * OsuHitObject.OBJECT_RADIUS; + var vertices = new List(); slider.Path.GetPathToProgress(vertices, 0, 1); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs index 2ecfea2e3e..ec3a1d0034 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs @@ -1,9 +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.Allocation; -using osu.Framework.Bindables; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; @@ -11,8 +8,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class SliderCirclePiece : HitCirclePiece { - private readonly IBindable pathBindable = new Bindable(); - private readonly Slider slider; private readonly SliderPosition position; @@ -23,13 +18,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components this.position = position; } - [BackgroundDependencyLoader] - private void load() - { - pathBindable.BindTo(slider.PathBindable); - pathBindable.BindValueChanged(_ => UpdatePosition(), true); - } - protected override void UpdatePosition() { switch (position) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index ae94848c81..e2084bbb7c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -52,13 +52,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components private void load(OsuColour colours) { Colour = colours.Yellow; - - PositionBindable.BindValueChanged(_ => updatePosition(), true); - StackHeightBindable.BindValueChanged(_ => updatePosition()); - ScaleBindable.BindValueChanged(scale => ring.Scale = new Vector2(scale.NewValue), true); } - private void updatePosition() => Position = spinner.Position; + protected override void Update() + { + base.Update(); + + Position = spinner.Position; + ring.Scale = new Vector2(spinner.Scale); + } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); } From 4fc37d11376980b2fc34c616b247e8fbaca8b640 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 27 Sep 2019 18:01:55 +0900 Subject: [PATCH 163/966] Remove SliderPiece + HitObjectPiece --- .../HitCircles/Components/HitCirclePiece.cs | 4 ++-- .../Edit/Blueprints/HitObjectPiece.cs | 21 ------------------- .../Edit/Blueprints/SliderPiece.cs | 21 ------------------- .../Components/PathControlPointVisualiser.cs | 3 +-- .../Sliders/Components/SliderBodyPiece.cs | 6 +++--- .../Spinners/Components/SpinnerPiece.cs | 3 +-- 6 files changed, 7 insertions(+), 51 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs delete mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index 99928cdad9..5e46b3ace4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -10,12 +11,11 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { - public class HitCirclePiece : HitObjectPiece + public class HitCirclePiece : CompositeDrawable { private readonly HitCircle hitCircle; public HitCirclePiece(HitCircle hitCircle) - : base(hitCircle) { this.hitCircle = hitCircle; Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs deleted file mode 100644 index 3d7d609c6b..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs +++ /dev/null @@ -1,21 +0,0 @@ -// 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.Containers; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Edit.Blueprints -{ - /// - /// A piece of a blueprint which responds to changes in the state of a . - /// - public abstract class HitObjectPiece : CompositeDrawable - { - protected readonly OsuHitObject HitObject; - - protected HitObjectPiece(OsuHitObject hitObject) - { - HitObject = hitObject; - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs deleted file mode 100644 index e0fcf8a000..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Edit.Blueprints -{ - /// - /// A piece of a blueprint which responds to changes in the state of a . - /// - public abstract class SliderPiece : HitObjectPiece - { - protected readonly Slider Slider; - - protected SliderPiece(Slider slider) - : base(slider) - { - Slider = slider; - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 3d8e014551..24fcc460d1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -7,14 +7,13 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class PathControlPointVisualiser : SliderPiece + public class PathControlPointVisualiser : CompositeDrawable { private readonly Slider slider; private readonly Container pieces; public PathControlPointVisualiser(Slider slider) - : base(slider) { this.slider = slider; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index aea17a4b8f..239feee431 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -11,13 +12,12 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class SliderBodyPiece : SliderPiece + public class SliderBodyPiece : CompositeDrawable { private readonly Slider slider; private readonly ManualSliderBody body; public SliderBodyPiece(Slider slider) - : base(slider) { this.slider = slider; @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components base.Update(); Position = slider.StackedPosition; - body.PathRadius = HitObject.Scale * OsuHitObject.OBJECT_RADIUS; + body.PathRadius = slider.Scale * OsuHitObject.OBJECT_RADIUS; var vertices = new List(); slider.Path.GetPathToProgress(vertices, 0, 1); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index e2084bbb7c..5dab501a24 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -12,14 +12,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { - public class SpinnerPiece : HitObjectPiece + public class SpinnerPiece : CompositeDrawable { private readonly Spinner spinner; private readonly CircularContainer circle; private readonly RingPiece ring; public SpinnerPiece(Spinner spinner) - : base(spinner) { this.spinner = spinner; From bddaead72e5b650b4e2e0205572b3ac232c865bf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 27 Sep 2019 18:45:22 +0900 Subject: [PATCH 164/966] Make hitobject pieces able to update dynamically --- .../Edit/Blueprints/BlueprintPiece.cs | 25 +++++++++++++ .../HitCircles/Components/HitCirclePiece.cs | 18 +++------- .../HitCircles/HitCirclePlacementBlueprint.cs | 11 +++++- .../HitCircles/HitCircleSelectionBlueprint.cs | 13 +++++-- .../Edit/Blueprints/OsuSelectionBlueprint.cs | 7 ++-- .../Components/PathControlPointPiece.cs | 2 +- .../Sliders/Components/SliderBodyPiece.cs | 21 ++++------- .../Sliders/Components/SliderCirclePiece.cs | 35 ------------------- .../Sliders/SliderCircleSelectionBlueprint.cs | 21 ++++++++--- .../Sliders/SliderPlacementBlueprint.cs | 15 ++++++-- .../Sliders/SliderSelectionBlueprint.cs | 16 ++++++--- .../Spinners/Components/SpinnerPiece.cs | 16 +++------ .../Spinners/SpinnerPlacementBlueprint.cs | 9 ++++- .../Spinners/SpinnerSelectionBlueprint.cs | 11 ++++-- 14 files changed, 125 insertions(+), 95 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs delete mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs new file mode 100644 index 0000000000..95e926fdfa --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs @@ -0,0 +1,25 @@ +// 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.Containers; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Blueprints +{ + /// + /// A piece of a selection or placement blueprint which visualises an . + /// + /// The type of which this visualises. + public abstract class BlueprintPiece : CompositeDrawable + where T : OsuHitObject + { + /// + /// Updates this using the properties of a . + /// + /// The to reference properties from. + public virtual void UpdateFrom(T hitObject) + { + Position = hitObject.Position; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index 5e46b3ace4..2b6b93a590 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -11,17 +10,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { - public class HitCirclePiece : CompositeDrawable + public class HitCirclePiece : BlueprintPiece { - private readonly HitCircle hitCircle; - - public HitCirclePiece(HitCircle hitCircle) + public HitCirclePiece() { - this.hitCircle = hitCircle; Origin = Anchor.Centre; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - Scale = new Vector2(hitCircle.Scale); CornerRadius = Size.X / 2; InternalChild = new RingPiece(); @@ -33,14 +28,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components Colour = colours.Yellow; } - protected override void Update() + public override void UpdateFrom(HitCircle hitObject) { - base.Update(); + base.UpdateFrom(hitObject); - UpdatePosition(); - Scale = new Vector2(hitCircle.Scale); + Scale = new Vector2(hitObject.Scale); } - - protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index a4050f0c31..cccef52737 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -13,10 +13,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { public new HitCircle HitObject => (HitCircle)base.HitObject; + private readonly HitCirclePiece circlePiece; + public HitCirclePlacementBlueprint() : base(new HitCircle()) { - InternalChild = new HitCirclePiece(HitObject); + InternalChild = circlePiece = new HitCirclePiece(); } protected override void LoadComplete() @@ -27,6 +29,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero; } + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(HitObject); + } + protected override bool OnClick(ClickEvent e) { HitObject.StartTime = EditorClock.CurrentTime; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 83787e2219..430d4a0222 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -7,12 +7,21 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCircleSelectionBlueprint : OsuSelectionBlueprint + public class HitCircleSelectionBlueprint : OsuSelectionBlueprint { + private readonly HitCirclePiece circlePiece; + public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = new HitCirclePiece((HitCircle)hitCircle.HitObject); + InternalChild = circlePiece = new HitCirclePiece(); + } + + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(HitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index dd524252f3..2e4b990db8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -7,11 +7,12 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { - public class OsuSelectionBlueprint : SelectionBlueprint + public abstract class OsuSelectionBlueprint : SelectionBlueprint + where T : OsuHitObject { - protected OsuHitObject OsuObject => (OsuHitObject)HitObject.HitObject; + protected new T HitObject => (T)base.HitObject.HitObject; - public OsuSelectionBlueprint(DrawableHitObject hitObject) + protected OsuSelectionBlueprint(DrawableHitObject hitObject) : base(hitObject) { } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index e257369ad9..3aec7c2872 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class PathControlPointPiece : CompositeDrawable + public class PathControlPointPiece : BlueprintPiece { private readonly Slider slider; private readonly int index; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 239feee431..d28cf7b492 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -12,18 +11,15 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class SliderBodyPiece : CompositeDrawable + public class SliderBodyPiece : BlueprintPiece { - private readonly Slider slider; private readonly ManualSliderBody body; - public SliderBodyPiece(Slider slider) + public SliderBodyPiece() { - this.slider = slider; - InternalChild = body = new ManualSliderBody { - AccentColour = Color4.Transparent, + AccentColour = Color4.Transparent }; } @@ -33,17 +29,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components body.BorderColour = colours.Yellow; } - private void updatePosition() => Position = slider.StackedPosition; - - protected override void Update() + public override void UpdateFrom(Slider hitObject) { - base.Update(); + base.UpdateFrom(hitObject); - Position = slider.StackedPosition; - body.PathRadius = slider.Scale * OsuHitObject.OBJECT_RADIUS; + body.PathRadius = hitObject.Scale * OsuHitObject.OBJECT_RADIUS; var vertices = new List(); - slider.Path.GetPathToProgress(vertices, 0, 1); + hitObject.Path.GetPathToProgress(vertices, 0, 1); body.SetVertices(vertices); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs deleted file mode 100644 index ec3a1d0034..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components -{ - public class SliderCirclePiece : HitCirclePiece - { - private readonly Slider slider; - private readonly SliderPosition position; - - public SliderCirclePiece(Slider slider, SliderPosition position) - : base(slider.HeadCircle) - { - this.slider = slider; - this.position = position; - } - - protected override void UpdatePosition() - { - switch (position) - { - case SliderPosition.Start: - Position = slider.StackedPosition + slider.Path.PositionAt(0); - break; - - case SliderPosition.End: - Position = slider.StackedPosition + slider.Path.PositionAt(1); - break; - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index c9f005495c..8f9a9c3a64 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -1,22 +1,33 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint + public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint { - public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) - : base(hitObject) + private readonly SliderPosition position; + private readonly HitCirclePiece circlePiece; + + public SliderCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) + : base(slider) { - InternalChild = new SliderCirclePiece(slider, position); + this.position = position; + InternalChild = circlePiece = new HitCirclePiece(); Select(); } + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(position == SliderPosition.Start ? HitObject.HeadCircle : HitObject.TailCircle); + } + // Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input. public override bool HandlePositionalInput => false; } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 55de626d7d..4c281a0e7d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osuTK; using osuTK.Input; @@ -21,6 +22,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; + private SliderBodyPiece bodyPiece; + private HitCirclePiece headCirclePiece; + private HitCirclePiece tailCirclePiece; + private readonly List segments = new List(); private Vector2 cursor; @@ -38,9 +43,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { InternalChildren = new Drawable[] { - new SliderBodyPiece(HitObject), - new SliderCirclePiece(HitObject, SliderPosition.Start), - new SliderCirclePiece(HitObject, SliderPosition.End), + bodyPiece = new SliderBodyPiece(), + headCirclePiece = new HitCirclePiece(), + tailCirclePiece = new HitCirclePiece(), new PathControlPointVisualiser(HitObject), }; @@ -130,6 +135,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { var newControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); HitObject.Path = new SliderPath(newControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, newControlPoints); + + bodyPiece.UpdateFrom(HitObject); + headCirclePiece.UpdateFrom(HitObject.HeadCircle); + tailCirclePiece.UpdateFrom(HitObject.TailCircle); } private void setState(PlacementState newState) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index fb8c081ff7..bc760c9456 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -9,8 +9,9 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderSelectionBlueprint : OsuSelectionBlueprint + public class SliderSelectionBlueprint : OsuSelectionBlueprint { + private readonly SliderBodyPiece bodyPiece; private readonly SliderCircleSelectionBlueprint headBlueprint; public SliderSelectionBlueprint(DrawableSlider slider) @@ -20,13 +21,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders InternalChildren = new Drawable[] { - new SliderBodyPiece(sliderObject), - headBlueprint = new SliderCircleSelectionBlueprint(slider.HeadCircle, sliderObject, SliderPosition.Start), - new SliderCircleSelectionBlueprint(slider.TailCircle, sliderObject, SliderPosition.End), + bodyPiece = new SliderBodyPiece(), + headBlueprint = new SliderCircleSelectionBlueprint(slider, SliderPosition.Start), + new SliderCircleSelectionBlueprint(slider, SliderPosition.End), new PathControlPointVisualiser(sliderObject), }; } + protected override void Update() + { + base.Update(); + + bodyPiece.UpdateFrom(HitObject); + } + public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index 5dab501a24..65c8720031 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -12,16 +12,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { - public class SpinnerPiece : CompositeDrawable + public class SpinnerPiece : BlueprintPiece { - private readonly Spinner spinner; private readonly CircularContainer circle; private readonly RingPiece ring; - public SpinnerPiece(Spinner spinner) + public SpinnerPiece() { - this.spinner = spinner; - Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; @@ -43,8 +40,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components Origin = Anchor.Centre } }; - - ring.Scale = new Vector2(spinner.Scale); } [BackgroundDependencyLoader] @@ -53,12 +48,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components Colour = colours.Yellow; } - protected override void Update() + public override void UpdateFrom(Spinner hitObject) { - base.Update(); + base.UpdateFrom(hitObject); - Position = spinner.Position; - ring.Scale = new Vector2(spinner.Scale); + ring.Scale = new Vector2(hitObject.Scale); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 03d761c67f..8d9dea736b 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -21,7 +21,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners public SpinnerPlacementBlueprint() : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) { - InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; + InternalChild = piece = new SpinnerPiece { Alpha = 0.5f }; + } + + protected override void Update() + { + base.Update(); + + piece.UpdateFrom(HitObject); } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs index 25cef3b251..f05d4f8435 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs @@ -8,14 +8,21 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerSelectionBlueprint : OsuSelectionBlueprint + public class SpinnerSelectionBlueprint : OsuSelectionBlueprint { private readonly SpinnerPiece piece; public SpinnerSelectionBlueprint(DrawableSpinner spinner) : base(spinner) { - InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); + InternalChild = piece = new SpinnerPiece(); + } + + protected override void Update() + { + base.Update(); + + piece.UpdateFrom(HitObject); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); From 3af7c910fb311ac4319e9b2eb218926e6b52c04a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2019 19:09:07 +0000 Subject: [PATCH 165/966] Bump Humanizer from 2.7.2 to 2.7.9 Bumps [Humanizer](https://github.com/Humanizr/Humanizer) from 2.7.2 to 2.7.9. - [Release notes](https://github.com/Humanizr/Humanizer/releases) - [Changelog](https://github.com/Humanizr/Humanizer/blob/master/release_notes.md) - [Commits](https://github.com/Humanizr/Humanizer/compare/v2.7.2...v2.7.9) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 83632f3d41..8fd5f1c3cd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -21,7 +21,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 30f1da362d..521552bd4b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -113,7 +113,7 @@ - + From fb9f21237ebb66b2e0631975d12d65b4f877c8e7 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 28 Sep 2019 04:18:16 +0300 Subject: [PATCH 166/966] Reset track adjustments on resuming from another screen --- osu.Game/Overlays/MusicController.cs | 6 +++--- osu.Game/Screens/Select/SongSelect.cs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index db94b0278f..172ae4e5cb 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -57,7 +57,7 @@ namespace osu.Game.Overlays protected override void LoadComplete() { beatmap.BindValueChanged(beatmapChanged, true); - mods.BindValueChanged(_ => updateAudioAdjustments(), true); + mods.BindValueChanged(_ => ResetTrackAdjustments(), true); base.LoadComplete(); } @@ -213,12 +213,12 @@ namespace osu.Game.Overlays current = beatmap.NewValue; TrackChanged?.Invoke(current, direction); - updateAudioAdjustments(); + ResetTrackAdjustments(); queuedDirection = null; } - private void updateAudioAdjustments() + public void ResetTrackAdjustments() { var track = current?.Track; if (track == null) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index fca801ce78..d40dd9414a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -490,6 +490,7 @@ namespace osu.Game.Screens.Select BeatmapDetails.Leaderboard.RefreshScores(); Beatmap.Value.Track.Looping = true; + music?.ResetTrackAdjustments(); if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) { From 2487d4f0f208524b433dff5dd6395b61268498a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Sep 2019 11:58:27 +0200 Subject: [PATCH 167/966] Migrate beatmap carousel test to AddUntilStep Due to non-deterministic test failures in TestSceneBeatmapCarousel, migrate the checkSelected helper step from AddAssert to AddUntilStep. This adds more leniency for performance-related issues while still checking the desired behaviour. --- osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index f12a613bf1..51dc11ebf8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet); private void checkSelected(int set, int? diff = null) => - AddAssert($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () => + AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () => { if (diff != null) return carousel.SelectedBeatmap == carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff.Value - 1).First(); From a45f8c968b4669ca345089670455ce740afeb7a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 28 Sep 2019 20:21:51 +0800 Subject: [PATCH 168/966] Rename and add simple xmldoc --- osu.Game/Configuration/SessionStatics.cs | 9 ++++++--- osu.Game/Screens/Menu/MainMenu.cs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index b4b5e914bb..818a95c0be 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -3,15 +3,18 @@ namespace osu.Game.Configuration { - public class SessionStatics : InMemoryConfigManager + /// + /// Stores global per-session statics. These will not be stored after exiting the game. + /// + public class SessionStatics : InMemoryConfigManager { protected override void InitialiseDefaults() { - Set(Statics.LoginOverlayDisplayed, false); + Set(Static.LoginOverlayDisplayed, false); } } - public enum Statics + public enum Static { LoginOverlayDisplayed, } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 004bba20d4..16e9d67cc3 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Menu private void load(DirectOverlay direct, SettingsOverlay settings, OsuConfigManager config, SessionStatics statics) { holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); - loginDisplayed = statics.GetBindable(Statics.LoginOverlayDisplayed); + loginDisplayed = statics.GetBindable(Static.LoginOverlayDisplayed); if (host.CanExit) { From 52b044b7f60b055df4baccedbc902eb7142788eb Mon Sep 17 00:00:00 2001 From: V1ntagezTV Date: Sun, 29 Sep 2019 00:10:17 +0500 Subject: [PATCH 169/966] Add random intro! --- osu.Game/Configuration/IntroSequence.cs | 3 ++- osu.Game/Screens/Loader.cs | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/IntroSequence.cs b/osu.Game/Configuration/IntroSequence.cs index 1eb953be36..1ee7da8bac 100644 --- a/osu.Game/Configuration/IntroSequence.cs +++ b/osu.Game/Configuration/IntroSequence.cs @@ -6,6 +6,7 @@ namespace osu.Game.Configuration public enum IntroSequence { Circles, - Triangles + Triangles, + Random } } diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 850349272e..7d2ad0e0ad 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -12,6 +13,7 @@ using osu.Framework.Screens; using osu.Game.Configuration; using IntroSequence = osu.Game.Configuration.IntroSequence; + namespace osu.Game.Screens { public class Loader : StartupScreen @@ -58,9 +60,16 @@ namespace osu.Game.Screens } private IntroScreen getIntroSequence() - { + {//вот именно что не показывает ни всплывающих подсказок нихера + Random random = new Random(); switch (introSequence) { + case IntroSequence.Random: + if (random.Next(2) == 0) + return new IntroCircles(); + else + return new IntroTriangles(); + case IntroSequence.Circles: return new IntroCircles(); From 1babd139bc066c1d49e48fa4cf3575784d010eaf Mon Sep 17 00:00:00 2001 From: V1ntagezTV Date: Sun, 29 Sep 2019 00:22:23 +0500 Subject: [PATCH 170/966] remove needless blank --- osu.Game/Screens/Loader.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 7d2ad0e0ad..c17463388a 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -13,7 +13,6 @@ using osu.Framework.Screens; using osu.Game.Configuration; using IntroSequence = osu.Game.Configuration.IntroSequence; - namespace osu.Game.Screens { public class Loader : StartupScreen From 2681e2064ae40da81da7ac1b2962481556025d10 Mon Sep 17 00:00:00 2001 From: V1ntagezTV Date: Sun, 29 Sep 2019 00:34:09 +0500 Subject: [PATCH 171/966] remove comment --- osu.Game/Screens/Loader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index c17463388a..75ed74978f 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens } private IntroScreen getIntroSequence() - {//вот именно что не показывает ни всплывающих подсказок нихера + { Random random = new Random(); switch (introSequence) { From 9f1c3787333dbaa7957992e0248e317f46c2797c Mon Sep 17 00:00:00 2001 From: V1ntagezTV Date: Sun, 29 Sep 2019 00:35:47 +0500 Subject: [PATCH 172/966] moved into the switch case --- osu.Game/Screens/Loader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 75ed74978f..fb49c8a574 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -60,10 +60,10 @@ namespace osu.Game.Screens private IntroScreen getIntroSequence() { - Random random = new Random(); switch (introSequence) { case IntroSequence.Random: + var random = new Random(); if (random.Next(2) == 0) return new IntroCircles(); else From 740efa57477f75da8078fb0d86e73bc603e7bb64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 29 Sep 2019 12:13:41 +0800 Subject: [PATCH 173/966] Handle potential null case --- osu.Game/Overlays/MusicController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 172ae4e5cb..49d16a4f3e 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -75,7 +75,7 @@ namespace osu.Game.Overlays /// /// Returns whether the current beatmap track is playing. /// - public bool IsPlaying => beatmap.Value.Track.IsRunning; + public bool IsPlaying => beatmap.Value?.Track.IsRunning ?? false; private void handleBeatmapAdded(BeatmapSetInfo set) => Schedule(() => beatmapSets.Add(set)); From 539f3329cef87bf1024b569a6ae77e033316e15e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 29 Sep 2019 12:23:18 +0800 Subject: [PATCH 174/966] Rename method to match new behaviour --- .../SongSelect/TestSceneBeatmapCarousel.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 51dc11ebf8..90c6c9065c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.SongSelect private void ensureRandomFetchSuccess() => AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet); - private void checkSelected(int set, int? diff = null) => + private void waitForSelection(int set, int? diff = null) => AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () => { if (diff != null) @@ -168,24 +168,24 @@ namespace osu.Game.Tests.Visual.SongSelect loadBeatmaps(); advanceSelection(direction: 1, diff: false); - checkSelected(1, 1); + waitForSelection(1, 1); advanceSelection(direction: 1, diff: true); - checkSelected(1, 2); + waitForSelection(1, 2); advanceSelection(direction: -1, diff: false); - checkSelected(set_count, 1); + waitForSelection(set_count, 1); advanceSelection(direction: -1, diff: true); - checkSelected(set_count - 1, 3); + waitForSelection(set_count - 1, 3); advanceSelection(diff: false); advanceSelection(diff: false); - checkSelected(1, 2); + waitForSelection(1, 2); advanceSelection(direction: -1, diff: true); advanceSelection(direction: -1, diff: true); - checkSelected(set_count, 3); + waitForSelection(set_count, 3); } /// @@ -203,10 +203,10 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Filter", () => carousel.Filter(new FilterCriteria { SearchText = "set #3!" }, false)); checkVisibleItemCount(diff: false, count: 1); checkVisibleItemCount(diff: true, count: 3); - checkSelected(3, 1); + waitForSelection(3, 1); advanceSelection(diff: true, count: 4); - checkSelected(3, 2); + waitForSelection(3, 2); AddStep("Un-filter (debounce)", () => carousel.Filter(new FilterCriteria())); AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); @@ -217,10 +217,10 @@ namespace osu.Game.Tests.Visual.SongSelect setSelected(1, 2); AddStep("Filter some difficulties", () => carousel.Filter(new FilterCriteria { SearchText = "Normal" }, false)); - checkSelected(1, 1); + waitForSelection(1, 1); AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false)); - checkSelected(1, 1); + waitForSelection(1, 1); AddStep("Filter all", () => carousel.Filter(new FilterCriteria { SearchText = "Dingo" }, false)); @@ -249,7 +249,7 @@ namespace osu.Game.Tests.Visual.SongSelect IsLowerInclusive = true } }, false)); - checkSelected(3, 2); + waitForSelection(3, 2); AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false)); } @@ -317,7 +317,7 @@ namespace osu.Game.Tests.Visual.SongSelect checkVisibleItemCount(false, set_count); - checkSelected(set_count); + waitForSelection(set_count); } /// @@ -343,11 +343,11 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selection is non-null", () => currentSelection != null); AddStep("Remove selected", () => carousel.RemoveBeatmapSet(carousel.SelectedBeatmapSet)); - checkSelected(2); + waitForSelection(2); AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); - checkSelected(1); + waitForSelection(1); AddUntilStep("Remove all", () => { @@ -390,17 +390,17 @@ namespace osu.Game.Tests.Visual.SongSelect checkVisibleItemCount(true, 2); advanceSelection(true); - checkSelected(1, 3); + waitForSelection(1, 3); setHidden(3); - checkSelected(1, 1); + waitForSelection(1, 1); setHidden(2, false); advanceSelection(true); - checkSelected(1, 2); + waitForSelection(1, 2); setHidden(1); - checkSelected(1, 2); + waitForSelection(1, 2); setHidden(2); checkNoSelection(); From ce62f3c75b8e2e896053bbf61291bb31404c2775 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 29 Sep 2019 14:35:35 +0800 Subject: [PATCH 175/966] Simplify and future-proof random retrieval method Will support future added intros without further code changes. Also uses RNG instead of `new Random`. --- osu.Game/Screens/Loader.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index fb49c8a574..41ee01be20 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.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 System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shaders; +using osu.Framework.MathUtils; using osu.Game.Screens.Menu; using osuTK; using osu.Framework.Screens; @@ -60,15 +60,11 @@ namespace osu.Game.Screens private IntroScreen getIntroSequence() { + if (introSequence == IntroSequence.Random) + introSequence = (IntroSequence)RNG.Next(0, (int)IntroSequence.Random); + switch (introSequence) { - case IntroSequence.Random: - var random = new Random(); - if (random.Next(2) == 0) - return new IntroCircles(); - else - return new IntroTriangles(); - case IntroSequence.Circles: return new IntroCircles(); From 97a0e0097f6e5f4fe7de2b5d4000e5c48df9cd5a Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 29 Sep 2019 14:56:33 +0300 Subject: [PATCH 176/966] Add testing --- .../Visual/Online/TestSceneUserProfileOverlay.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 93e6607ac5..c0457ba0ff 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -106,6 +106,14 @@ namespace osu.Game.Tests.Visual.Online Country = new Country { FullName = @"Japan", FlagName = @"JP" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" }, api.IsLoggedIn)); + AddStep("Show bancho", () => profile.ShowUser(new User + { + Username = @"BanchoBot", + Id = 3, + IsBot = true, + Country = new Country { FullName = @"Saint Helena", FlagName = @"SH" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c4.jpg" + }, api.IsLoggedIn)); AddStep("Hide", profile.Hide); AddStep("Show without reload", profile.Show); From f24ac04bebbcbbc0ca5d0679172d3fbe6efd6854 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 29 Sep 2019 15:18:29 +0300 Subject: [PATCH 177/966] Add suggested blank line for consistency --- osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index c0457ba0ff..98da63508b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -106,6 +106,7 @@ namespace osu.Game.Tests.Visual.Online Country = new Country { FullName = @"Japan", FlagName = @"JP" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" }, api.IsLoggedIn)); + AddStep("Show bancho", () => profile.ShowUser(new User { Username = @"BanchoBot", From 9f498d29908a94f2a70a7e3d390a4202d9a5bdec Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 29 Sep 2019 19:25:44 +0200 Subject: [PATCH 178/966] Log the exception that caused to loading of rulesets to fail. --- osu.Game/Rulesets/RulesetStore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 2d8c9f5b49..a94b0e0c06 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -135,9 +135,9 @@ namespace osu.Game.Rulesets foreach (string file in files.Where(f => !Path.GetFileName(f).Contains("Tests"))) loadRulesetFromFile(file); } - catch + catch(Exception e) { - Logger.Log($"Could not load rulesets from directory {Environment.CurrentDirectory}"); + Logger.Error(e, $"Could not load rulesets from directory {Environment.CurrentDirectory}"); } } From 42d1379848fa03611cda80eb2336838ddf3165d3 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 29 Sep 2019 20:40:10 +0200 Subject: [PATCH 179/966] Load the rulesets lasily --- osu.Game/Rulesets/RulesetStore.cs | 95 ++++++++++++++++--------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 2d8c9f5b49..6392f982fb 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -16,17 +16,11 @@ namespace osu.Game.Rulesets /// public class RulesetStore : DatabaseBackedStore { - private static readonly Dictionary loaded_assemblies = new Dictionary(); + private static readonly Lazy> loaded_assemblies = new Lazy>(() => loadRulesets()); static RulesetStore() { AppDomain.CurrentDomain.AssemblyResolve += currentDomain_AssemblyResolve; - - // On android in release configuration assemblies are loaded from the apk directly into memory. - // We cannot read assemblies from cwd, so should check loaded assemblies instead. - loadFromAppDomain(); - - loadFromDisk(); } public RulesetStore(IDatabaseContextFactory factory) @@ -54,7 +48,7 @@ namespace osu.Game.Rulesets /// public IEnumerable AvailableRulesets { get; private set; } - private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); + private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Value.Keys.FirstOrDefault(a => a.FullName == args.Name); private const string ruleset_library_prefix = "osu.Game.Rulesets"; @@ -64,7 +58,7 @@ namespace osu.Game.Rulesets { var context = usage.Context; - var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); + var instances = loaded_assemblies.Value.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID)) @@ -113,8 +107,39 @@ namespace osu.Game.Rulesets } } - private static void loadFromAppDomain() + /// + /// Loads the rulesets that are in the current appdomain an in the current directory. + /// + /// The rulesets that were loaded. + private static Dictionary loadRulesets() { + var rulesets = new Dictionary(); + + foreach (var rulesetAssembly in getRulesetAssemblies()) + { + try + { + rulesets[rulesetAssembly] = rulesetAssembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); + } + catch (Exception e) + { + Logger.Error(e, $"Failed to add ruleset {rulesetAssembly}"); + } + } + + return rulesets; + } + + /// + /// Scans the current appdomain and current directory for ruleset assemblies. + /// Rulesets that were found in the current directory are automaticly loaded. + /// + /// The ruleset assemblies that were found in the current appdomain or in the current directory. + private static IEnumerable getRulesetAssemblies() + { + var rulesetAssemblies = new HashSet(); + + // load from appdomain foreach (var ruleset in AppDomain.CurrentDomain.GetAssemblies()) { string rulesetName = ruleset.GetName().Name; @@ -122,55 +147,33 @@ namespace osu.Game.Rulesets if (!rulesetName.StartsWith(ruleset_library_prefix, StringComparison.InvariantCultureIgnoreCase) || ruleset.GetName().Name.Contains("Tests")) continue; - addRuleset(ruleset); + rulesetAssemblies.Add(ruleset); } - } - private static void loadFromDisk() - { + // load from current directory try { string[] files = Directory.GetFiles(Environment.CurrentDirectory, $"{ruleset_library_prefix}.*.dll"); foreach (string file in files.Where(f => !Path.GetFileName(f).Contains("Tests"))) - loadRulesetFromFile(file); + { + try + { + rulesetAssemblies.Add(Assembly.LoadFrom(file)); + } + catch (Exception e) + { + Logger.Error(e, $"Failed to load ruleset assembly {Path.GetFileNameWithoutExtension(file)}"); + return null; + } + } } catch { Logger.Log($"Could not load rulesets from directory {Environment.CurrentDirectory}"); } - } - private static void loadRulesetFromFile(string file) - { - var filename = Path.GetFileNameWithoutExtension(file); - - if (loaded_assemblies.Values.Any(t => t.Namespace == filename)) - return; - - try - { - addRuleset(Assembly.LoadFrom(file)); - } - catch (Exception e) - { - Logger.Error(e, $"Failed to load ruleset {filename}"); - } - } - - private static void addRuleset(Assembly assembly) - { - if (loaded_assemblies.ContainsKey(assembly)) - return; - - try - { - loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); - } - catch (Exception e) - { - Logger.Error(e, $"Failed to add ruleset {assembly}"); - } + return rulesetAssemblies; } } } From 351e89bf182faaaa342c2b0c78f63a10500af18d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Sep 2019 22:03:56 +0900 Subject: [PATCH 180/966] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 46fd5424df..51245351b6 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -62,6 +62,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8fd5f1c3cd..8cbc8b0af3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 521552bd4b..a15cae55c4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,8 +118,8 @@ - - + + From 04ac414249a30de3ea34a734a2c0e08183a27af7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 13:48:56 +0900 Subject: [PATCH 181/966] Fix memory leaks due to audio track recycle order --- osu.Game/Beatmaps/BindableBeatmap.cs | 23 ----------------------- osu.Game/OsuGameBase.cs | 6 ++++++ osu.Game/Tests/Visual/OsuTestScene.cs | 9 ++++++--- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/osu.Game/Beatmaps/BindableBeatmap.cs b/osu.Game/Beatmaps/BindableBeatmap.cs index af627cc6a9..39c633e282 100644 --- a/osu.Game/Beatmaps/BindableBeatmap.cs +++ b/osu.Game/Beatmaps/BindableBeatmap.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 System.Diagnostics; using osu.Framework.Bindables; namespace osu.Game.Beatmaps @@ -12,31 +11,9 @@ namespace osu.Game.Beatmaps /// public abstract class BindableBeatmap : NonNullableBindable { - private WorkingBeatmap lastBeatmap; - protected BindableBeatmap(WorkingBeatmap defaultValue) : base(defaultValue) { - BindValueChanged(b => updateAudioTrack(b.NewValue), true); - } - - private void updateAudioTrack(WorkingBeatmap beatmap) - { - var trackLoaded = lastBeatmap?.TrackLoaded ?? false; - - // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo) - if (!trackLoaded || lastBeatmap?.Track != beatmap.Track) - { - if (trackLoaded) - { - Debug.Assert(lastBeatmap != null); - Debug.Assert(lastBeatmap.Track != null); - - lastBeatmap.RecycleTrack(); - } - } - - lastBeatmap = beatmap; } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 59a5e38b2c..a9a9693c76 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -203,6 +203,12 @@ namespace osu.Game Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8)); beatmap = new OsuBindableBeatmap(defaultBeatmap); + beatmap.BindValueChanged(b => ScheduleAfterChildren(() => + { + // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo) + if (b.OldValue?.TrackLoaded == true && b.OldValue?.Track != b.NewValue?.Track) + b.OldValue.RecycleTrack(); + })); dependencies.CacheAs>(beatmap); dependencies.CacheAs(beatmap); diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 8e98d51962..cf128e058f 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -73,10 +73,13 @@ namespace osu.Game.Tests.Visual // This is the earliest we can get OsuGameBase, which is used by the dummy working beatmap to find textures var working = new DummyWorkingBeatmap(parent.Get(), parent.Get()); - beatmap = new OsuTestBeatmap(working) + beatmap = new OsuTestBeatmap(working) { Default = working }; + beatmap.BindValueChanged(b => ScheduleAfterChildren(() => { - Default = working - }; + // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo) + if (b.OldValue?.TrackLoaded == true && b.OldValue?.Track != b.NewValue?.Track) + b.OldValue.RecycleTrack(); + })); Dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); From ce609302edd25e0a59a36d64d81b2bfc36c2b344 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 15:41:01 +0900 Subject: [PATCH 182/966] Fix CI error --- osu.Game/Rulesets/RulesetStore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index a94b0e0c06..47aad43966 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -135,7 +135,7 @@ namespace osu.Game.Rulesets foreach (string file in files.Where(f => !Path.GetFileName(f).Contains("Tests"))) loadRulesetFromFile(file); } - catch(Exception e) + catch (Exception e) { Logger.Error(e, $"Could not load rulesets from directory {Environment.CurrentDirectory}"); } From cc533e8fe471c69bb0db52915a803ee1f7ad2a2f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 17:24:47 +0900 Subject: [PATCH 183/966] Remove BindableBeatmap --- osu.Game/Beatmaps/BindableBeatmap.cs | 19 ------------------- osu.Game/OsuGameBase.cs | 10 +--------- osu.Game/Tests/Visual/OsuTestScene.cs | 14 +++----------- 3 files changed, 4 insertions(+), 39 deletions(-) delete mode 100644 osu.Game/Beatmaps/BindableBeatmap.cs diff --git a/osu.Game/Beatmaps/BindableBeatmap.cs b/osu.Game/Beatmaps/BindableBeatmap.cs deleted file mode 100644 index 39c633e282..0000000000 --- a/osu.Game/Beatmaps/BindableBeatmap.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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.Bindables; - -namespace osu.Game.Beatmaps -{ - /// - /// A for the beatmap. - /// This should be used sparingly in-favour of . - /// - public abstract class BindableBeatmap : NonNullableBindable - { - protected BindableBeatmap(WorkingBeatmap defaultValue) - : base(defaultValue) - { - } - } -} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index a9a9693c76..8578517a17 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -202,7 +202,7 @@ namespace osu.Game // this adds a global reduction of track volume for the time being. Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8)); - beatmap = new OsuBindableBeatmap(defaultBeatmap); + beatmap = new NonNullableBindable(defaultBeatmap); beatmap.BindValueChanged(b => ScheduleAfterChildren(() => { // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo) @@ -298,14 +298,6 @@ namespace osu.Game public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray(); - private class OsuBindableBeatmap : BindableBeatmap - { - public OsuBindableBeatmap(WorkingBeatmap defaultValue) - : base(defaultValue) - { - } - } - private class OsuUserInputManager : UserInputManager { protected override MouseButtonEventManager CreateButtonManagerFor(MouseButton button) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index cf128e058f..96b39b303e 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -28,9 +28,9 @@ namespace osu.Game.Tests.Visual { [Cached(typeof(Bindable))] [Cached(typeof(IBindable))] - private OsuTestBeatmap beatmap; + private NonNullableBindable beatmap; - protected BindableBeatmap Beatmap => beatmap; + protected Bindable Beatmap => beatmap; [Cached] [Cached(typeof(IBindable))] @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual // This is the earliest we can get OsuGameBase, which is used by the dummy working beatmap to find textures var working = new DummyWorkingBeatmap(parent.Get(), parent.Get()); - beatmap = new OsuTestBeatmap(working) { Default = working }; + beatmap = new NonNullableBindable(working) { Default = working }; beatmap.BindValueChanged(b => ScheduleAfterChildren(() => { // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo) @@ -320,13 +320,5 @@ namespace osu.Game.Tests.Visual public void RunTestBlocking(TestScene test) => runner.RunTestBlocking(test); } - - private class OsuTestBeatmap : BindableBeatmap - { - public OsuTestBeatmap(WorkingBeatmap defaultValue) - : base(defaultValue) - { - } - } } } From a310c4b65f220afef633a4dc6ff9d8c58c89f0d2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:32:47 +0900 Subject: [PATCH 184/966] Make selection blueprints a bit more testable --- .../TestSceneHoldNoteSelectionBlueprint.cs | 4 ++- .../TestSceneNoteSelectionBlueprint.cs | 8 +++--- .../TestSceneSpinnerSelectionBlueprint.cs | 9 ++++--- .../Visual/SelectionBlueprintTestScene.cs | 26 +++++-------------- 4 files changed, 20 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs index 622d840a0c..5507ca2ba0 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs @@ -39,6 +39,8 @@ namespace osu.Game.Rulesets.Mania.Tests AccentColour = { Value = OsuColour.Gray(0.3f) } } }; + + AddBlueprint(new HoldNoteSelectionBlueprint(drawableObject)); } protected override void Update() @@ -52,6 +54,6 @@ namespace osu.Game.Rulesets.Mania.Tests } } - protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs index 6bb344f977..c0482e2150 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs @@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Mania.Tests { public class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene { - private readonly DrawableNote drawableObject; - protected override Container Content => content ?? base.Content; private readonly Container content; @@ -27,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.Tests var note = new Note { Column = 0 }; note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + DrawableNote drawableObject; + base.Content.Child = content = new ScrollingTestContainer(ScrollingDirection.Down) { Anchor = Anchor.Centre, @@ -34,8 +34,10 @@ namespace osu.Game.Rulesets.Mania.Tests Size = new Vector2(50, 20), Child = drawableObject = new DrawableNote(note) }; + + AddBlueprint(new NoteSelectionBlueprint(drawableObject)); } - protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs index c5cea76b14..1c195311a4 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs @@ -25,8 +25,6 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(SpinnerPiece) }; - private readonly DrawableSpinner drawableSpinner; - public TestSceneSpinnerSelectionBlueprint() { var spinner = new Spinner @@ -35,16 +33,21 @@ namespace osu.Game.Rulesets.Osu.Tests StartTime = -1000, EndTime = 2000 }; + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + DrawableSpinner drawableSpinner; + Add(new Container { RelativeSizeAxes = Axes.Both, Size = new Vector2(0.5f), Child = drawableSpinner = new DrawableSpinner(spinner) }); + + AddBlueprint(new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }); } - protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }; + protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(null) { Size = new Vector2(0.5f) }; } } diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index df3af2cc43..55dda03b16 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -1,10 +1,8 @@ // 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.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; @@ -12,8 +10,6 @@ namespace osu.Game.Tests.Visual { public abstract class SelectionBlueprintTestScene : OsuTestScene { - private SelectionBlueprint blueprint; - protected override Container Content => content ?? base.Content; private readonly Container content; @@ -26,23 +22,13 @@ namespace osu.Game.Tests.Visual }); } - [BackgroundDependencyLoader] - private void load() + protected void AddBlueprint(SelectionBlueprint blueprint) { - blueprint = CreateBlueprint(); - blueprint.Depth = float.MinValue; - blueprint.SelectionRequested += (_, __) => blueprint.Select(); - - Add(blueprint); - - AddStep("Select", () => blueprint.Select()); - AddStep("Deselect", () => blueprint.Deselect()); - } - - protected override bool OnClick(ClickEvent e) - { - blueprint.Deselect(); - return true; + Add(blueprint.With(d => + { + d.Depth = float.MinValue; + d.Select(); + })); } protected abstract SelectionBlueprint CreateBlueprint(); From ba5c9547e14a74af6cee3cbfd61a9066bb944734 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:33:08 +0900 Subject: [PATCH 185/966] Add more tests for hitcircle selection blueprint --- .../TestSceneHitCircleSelectionBlueprint.cs | 45 +++++++++++++++++-- .../HitCircles/HitCircleSelectionBlueprint.cs | 6 +-- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs index 32043bf5d7..7278d923c1 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs @@ -1,10 +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 NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -14,16 +16,53 @@ namespace osu.Game.Rulesets.Osu.Tests { public class TestSceneHitCircleSelectionBlueprint : SelectionBlueprintTestScene { - private readonly DrawableHitCircle drawableObject; + private HitCircle hitCircle; + private DrawableHitCircle drawableObject; + private TestBlueprint blueprint; - public TestSceneHitCircleSelectionBlueprint() + [SetUp] + public void Setup() => Schedule(() => { - var hitCircle = new HitCircle { Position = new Vector2(256, 192) }; + Clear(); + + hitCircle = new HitCircle { Position = new Vector2(256, 192) }; hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); Add(drawableObject = new DrawableHitCircle(hitCircle)); + AddBlueprint(blueprint = new TestBlueprint(drawableObject)); + }); + + [Test] + public void TestInitialState() + { + AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); + } + + [Test] + public void TestMoveHitObject() + { + AddStep("move hitobject", () => hitCircle.Position = new Vector2(300, 225)); + AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); + } + + [Test] + public void TestMoveAfterApplyingDefaults() + { + AddStep("apply defaults", () => hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 })); + AddStep("move hitobject", () => hitCircle.Position = new Vector2(300, 225)); + AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); } protected override SelectionBlueprint CreateBlueprint() => new HitCircleSelectionBlueprint(drawableObject); + + private class TestBlueprint : HitCircleSelectionBlueprint + { + public new HitCirclePiece CirclePiece => base.CirclePiece; + + public TestBlueprint(DrawableHitCircle hitCircle) + : base(hitCircle) + { + } + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 430d4a0222..a191dba8ff 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -9,19 +9,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { public class HitCircleSelectionBlueprint : OsuSelectionBlueprint { - private readonly HitCirclePiece circlePiece; + protected readonly HitCirclePiece CirclePiece; public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = circlePiece = new HitCirclePiece(); + InternalChild = CirclePiece = new HitCirclePiece(); } protected override void Update() { base.Update(); - circlePiece.UpdateFrom(HitObject); + CirclePiece.UpdateFrom(HitObject); } } } From 90ad1c5166fdc4dd116ff89554a585c28853774b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:33:24 +0900 Subject: [PATCH 186/966] Add more tests for slider selection blueprint --- .../TestSceneSliderSelectionBlueprint.cs | 79 ++++++++++++++++++- .../Sliders/SliderCircleSelectionBlueprint.cs | 7 +- .../Sliders/SliderSelectionBlueprint.cs | 17 ++-- 3 files changed, 90 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs index 8cf5a2f33e..61c8316ed9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs @@ -3,11 +3,14 @@ using System; using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; @@ -29,11 +32,16 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(PathControlPointPiece) }; - private readonly DrawableSlider drawableObject; + private Slider slider; + private DrawableSlider drawableObject; + private TestSliderBlueprint blueprint; - public TestSceneSliderSelectionBlueprint() + [SetUp] + public void Setup() => Schedule(() => { - var slider = new Slider + Clear(); + + slider = new Slider { Position = new Vector2(256, 192), Path = new SliderPath(PathType.Bezier, new[] @@ -47,8 +55,73 @@ namespace osu.Game.Rulesets.Osu.Tests slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); Add(drawableObject = new DrawableSlider(slider)); + AddBlueprint(blueprint = new TestSliderBlueprint(drawableObject)); + }); + + [Test] + public void TestInitialState() + { + checkPositions(); + } + + [Test] + public void TestMoveHitObject() + { + moveHitObject(); + checkPositions(); + } + + [Test] + public void TestMoveAfterApplyingDefaults() + { + AddStep("apply defaults", () => slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 })); + moveHitObject(); + checkPositions(); + } + + private void moveHitObject() + { + AddStep("move hitobject", () => + { + slider.Position = new Vector2(300, 225); + }); + } + + private void checkPositions() + { + AddAssert("body positioned correctly", () => blueprint.BodyPiece.Position == slider.Position); + + AddAssert("head positioned correctly", + () => Precision.AlmostEquals(blueprint.HeadBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.HeadCircle.ScreenSpaceDrawQuad.Centre)); + + AddAssert("tail positioned correctly", + () => Precision.AlmostEquals(blueprint.TailBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.TailCircle.ScreenSpaceDrawQuad.Centre)); } protected override SelectionBlueprint CreateBlueprint() => new SliderSelectionBlueprint(drawableObject); + + private class TestSliderBlueprint : SliderSelectionBlueprint + { + public new SliderBodyPiece BodyPiece => base.BodyPiece; + public new TestSliderCircleBlueprint HeadBlueprint => (TestSliderCircleBlueprint)base.HeadBlueprint; + public new TestSliderCircleBlueprint TailBlueprint => (TestSliderCircleBlueprint)base.TailBlueprint; + + public TestSliderBlueprint(DrawableSlider slider) + : base(slider) + { + } + + protected override SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new TestSliderCircleBlueprint(slider, position); + } + + private class TestSliderCircleBlueprint : SliderCircleSelectionBlueprint + { + public new HitCirclePiece CirclePiece => base.CirclePiece; + + public TestSliderCircleBlueprint(DrawableSlider slider, SliderPosition position) + : base(slider, position) + { + } + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index 8f9a9c3a64..f09279ed73 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -9,14 +9,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint { + protected readonly HitCirclePiece CirclePiece; + private readonly SliderPosition position; - private readonly HitCirclePiece circlePiece; public SliderCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) : base(slider) { this.position = position; - InternalChild = circlePiece = new HitCirclePiece(); + InternalChild = CirclePiece = new HitCirclePiece(); Select(); } @@ -25,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { base.Update(); - circlePiece.UpdateFrom(position == SliderPosition.Start ? HitObject.HeadCircle : HitObject.TailCircle); + CirclePiece.UpdateFrom(position == SliderPosition.Start ? HitObject.HeadCircle : HitObject.TailCircle); } // Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input. diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index bc760c9456..fdeffc6f8a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -11,8 +11,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public class SliderSelectionBlueprint : OsuSelectionBlueprint { - private readonly SliderBodyPiece bodyPiece; - private readonly SliderCircleSelectionBlueprint headBlueprint; + protected readonly SliderBodyPiece BodyPiece; + protected readonly SliderCircleSelectionBlueprint HeadBlueprint; + protected readonly SliderCircleSelectionBlueprint TailBlueprint; public SliderSelectionBlueprint(DrawableSlider slider) : base(slider) @@ -21,9 +22,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders InternalChildren = new Drawable[] { - bodyPiece = new SliderBodyPiece(), - headBlueprint = new SliderCircleSelectionBlueprint(slider, SliderPosition.Start), - new SliderCircleSelectionBlueprint(slider, SliderPosition.End), + BodyPiece = new SliderBodyPiece(), + HeadBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.Start), + TailBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.End), new PathControlPointVisualiser(sliderObject), }; } @@ -32,9 +33,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { base.Update(); - bodyPiece.UpdateFrom(HitObject); + BodyPiece.UpdateFrom(HitObject); } - public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; + public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint; + + protected virtual SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new SliderCircleSelectionBlueprint(slider, position); } } From c5540048ab1608873b6377f2fa15bbd4b5b7ab01 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:39:06 +0900 Subject: [PATCH 187/966] Fix tail circle not moving with slider position changes --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index d8514092bc..3ed1f2cdde 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -54,13 +54,13 @@ namespace osu.Game.Rulesets.Osu.Objects { base.Position = value; + endPositionCache.Invalidate(); + if (HeadCircle != null) HeadCircle.Position = value; if (TailCircle != null) TailCircle.Position = EndPosition; - - endPositionCache.Invalidate(); } } From 208b9a4eba5c5df080683456afae698feafe99c9 Mon Sep 17 00:00:00 2001 From: Ganendra Afrasya Date: Tue, 1 Oct 2019 20:47:53 +0700 Subject: [PATCH 188/966] Add new virtual float for username to timestamp padding --- .../Visual/Online/TestSceneStandAloneChatDisplay.cs | 12 ++++++++++++ osu.Game/Online/Chat/StandAloneChatDisplay.cs | 1 + osu.Game/Overlays/Chat/ChatLine.cs | 8 +++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index 91006bc0d9..3c5641fcd6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -32,6 +32,12 @@ namespace osu.Game.Tests.Visual.Online Id = 4, }; + private readonly User longUsernameUser = new User + { + Username = "Very Long Long Username", + Id = 5, + }; + [Cached] private ChannelManager channelManager = new ChannelManager(); @@ -99,6 +105,12 @@ namespace osu.Game.Tests.Visual.Online Sender = admin, Content = "Okay okay, calm down guys. Let's do this!" })); + + AddStep("message from long username", () => testChannel.AddNewMessages(new Message(sequence++) + { + Sender = longUsernameUser, + Content = "Hi guys, my new username is lit!" + })); } } } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 9dab2f2aba..00defd5f34 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -146,6 +146,7 @@ namespace osu.Game.Online.Chat protected override float HorizontalPadding => 10; protected override float MessagePadding => 120; + protected override float TimestampPadding => 130; public StandAloneMessage(Message message) : base(message) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 7596231a3d..1f5f5d3ff6 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -31,7 +31,9 @@ namespace osu.Game.Overlays.Chat protected virtual float MessagePadding => default_message_padding; - private const float timestamp_padding = 65; + private const float default_timestamp_padding = 65; + + protected virtual float TimestampPadding => default_timestamp_padding; private const float default_horizontal_padding = 15; @@ -94,7 +96,7 @@ namespace osu.Game.Overlays.Chat Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - MaxWidth = default_message_padding - timestamp_padding + MaxWidth = default_message_padding - TimestampPadding }; if (hasBackground) @@ -149,7 +151,7 @@ namespace osu.Game.Overlays.Chat new MessageSender(message.Sender) { AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = timestamp_padding }, + Padding = new MarginPadding { Left = TimestampPadding }, Origin = Anchor.TopRight, Anchor = Anchor.TopRight, Child = effectedUsername, From 5f700f2ae9e57139cfa4aa0cb7e249363cc6d7e6 Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 1 Oct 2019 08:26:34 -0700 Subject: [PATCH 189/966] Simplify exit logic of screens with textboxes using back button receptor --- .../Graphics/UserInterface/FocusedTextBox.cs | 16 +++++----------- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 17 +---------------- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 4 ---- .../Chat/Selection/ChannelSelectionOverlay.cs | 1 - osu.Game/Overlays/ChatOverlay.cs | 1 - osu.Game/Overlays/Music/FilterControl.cs | 3 --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 1 - .../SearchableList/SearchableListOverlay.cs | 2 -- osu.Game/Overlays/SettingsPanel.cs | 1 - .../Screens/Multi/Lounge/LoungeSubScreen.cs | 2 -- osu.Game/Screens/Multi/Match/MatchSubScreen.cs | 9 +-------- osu.Game/Screens/Select/FilterControl.cs | 8 +------- osu.Game/Screens/Select/SongSelect.cs | 5 ----- 13 files changed, 8 insertions(+), 62 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index f873db0dcb..62fbb3592c 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -2,22 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using osuTK.Graphics; -using System; using osu.Framework.Allocation; using osu.Framework.Input.Events; using osu.Framework.Platform; using osu.Game.Input.Bindings; using osuTK.Input; +using osu.Framework.Input.Bindings; namespace osu.Game.Graphics.UserInterface { /// /// A textbox which holds focus eagerly. /// - public class FocusedTextBox : OsuTextBox + public class FocusedTextBox : OsuTextBox, IKeyBindingHandler { - public Action Exit; - private bool focus; private bool allowImmediateFocus => host?.OnScreenKeyboardOverlapsGameWindow != true; @@ -68,7 +66,7 @@ namespace osu.Game.Graphics.UserInterface return base.OnKeyDown(e); } - public override bool OnPressed(GlobalAction action) + public bool OnPressed(GlobalAction action) { if (action == GlobalAction.Back) { @@ -79,14 +77,10 @@ namespace osu.Game.Graphics.UserInterface } } - return base.OnPressed(action); + return false; } - protected override void KillFocus() - { - base.KillFocus(); - Exit?.Invoke(); - } + public bool OnReleased(GlobalAction action) => false; public override bool RequestsFocus => HoldFocus; } diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 89de91bc9b..1cac4d76ab 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -8,13 +8,11 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.Sprites; using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface { - public class OsuTextBox : TextBox, IKeyBindingHandler + public class OsuTextBox : TextBox { protected override float LeftRightPadding => 10; @@ -57,18 +55,5 @@ namespace osu.Game.Graphics.UserInterface } protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) }; - - public virtual bool OnPressed(GlobalAction action) - { - if (action == GlobalAction.Back) - { - KillFocus(); - return true; - } - - return false; - } - - public bool OnReleased(GlobalAction action) => false; } } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 9dab2f2aba..b9edc36dfb 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -21,8 +21,6 @@ namespace osu.Game.Online.Chat { public readonly Bindable Channel = new Bindable(); - public Action Exit; - private readonly FocusedTextBox textbox; protected ChannelManager ChannelManager; @@ -66,8 +64,6 @@ namespace osu.Game.Online.Chat Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, }); - - textbox.Exit += () => Exit?.Invoke(); } Channel.BindValueChanged(channelChanged); diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs index e0ded11ec9..621728830a 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs @@ -119,7 +119,6 @@ namespace osu.Game.Overlays.Chat.Selection { RelativeSizeAxes = Axes.X, PlaceholderText = @"Search", - Exit = Hide, }, }, }, diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 6f848c7627..0cadbdfd31 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -138,7 +138,6 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Height = 1, PlaceholderText = "type your message", - Exit = Hide, OnCommit = postMessage, ReleaseFocusOnCommit = false, HoldFocus = true, diff --git a/osu.Game/Overlays/Music/FilterControl.cs b/osu.Game/Overlays/Music/FilterControl.cs index 99017579a2..278bb55170 100644 --- a/osu.Game/Overlays/Music/FilterControl.cs +++ b/osu.Game/Overlays/Music/FilterControl.cs @@ -31,7 +31,6 @@ namespace osu.Game.Overlays.Music { RelativeSizeAxes = Axes.X, Height = 40, - Exit = () => ExitRequested?.Invoke(), }, new CollectionsDropdown { @@ -47,8 +46,6 @@ namespace osu.Game.Overlays.Music private void current_ValueChanged(ValueChangedEvent e) => FilterChanged?.Invoke(e.NewValue); - public Action ExitRequested; - public Action FilterChanged; public class FilterTextBox : SearchTextBox diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index ae81a6c117..bb88960280 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -63,7 +63,6 @@ namespace osu.Game.Overlays.Music { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - ExitRequested = Hide, FilterChanged = search => list.Filter(search), Padding = new MarginPadding(10), }, diff --git a/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs b/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs index 293ee4bcda..177f731f12 100644 --- a/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs +++ b/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs @@ -88,8 +88,6 @@ namespace osu.Game.Overlays.SearchableList }, }, }; - - Filter.Search.Exit = Hide; } protected override void Update() diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 9dd0def453..37e7b62483 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -91,7 +91,6 @@ namespace osu.Game.Overlays Top = 20, Bottom = 20 }, - Exit = Hide, }, Footer = CreateFooter() }, diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index 7f8e690516..0a48f761cf 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -69,8 +69,6 @@ namespace osu.Game.Screens.Multi.Lounge }, }, }; - - Filter.Search.Exit += this.Exit; } protected override void UpdateAfterChildren() diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs index f3e10db444..c2bb7da6b5 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs @@ -62,7 +62,6 @@ namespace osu.Game.Screens.Multi.Match [BackgroundDependencyLoader] private void load() { - MatchChatDisplay chat; Components.Header header; Info info; GridContainer bottomRow; @@ -122,7 +121,7 @@ namespace osu.Game.Screens.Multi.Match Vertical = 10, }, RelativeSizeAxes = Axes.Both, - Child = chat = new MatchChatDisplay + Child = new MatchChatDisplay { RelativeSizeAxes = Axes.Both } @@ -159,12 +158,6 @@ namespace osu.Game.Screens.Multi.Match bottomRow.FadeTo(settingsDisplayed ? 0 : 1, fade_duration, Easing.OutQuint); }, true); - chat.Exit += () => - { - if (this.IsCurrentScreen()) - this.Exit(); - }; - beatmapManager.ItemAdded += beatmapAdded; } diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 91f1ca0307..8755c3fda6 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -49,8 +49,6 @@ namespace osu.Game.Screens.Select return criteria; } - public Action Exit; - private readonly SearchTextBox searchTextBox; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => @@ -75,11 +73,7 @@ namespace osu.Game.Screens.Select Origin = Anchor.TopRight, Children = new Drawable[] { - searchTextBox = new SearchTextBox - { - RelativeSizeAxes = Axes.X, - Exit = () => Exit?.Invoke(), - }, + searchTextBox = new SearchTextBox { RelativeSizeAxes = Axes.X }, new Box { RelativeSizeAxes = Axes.X, diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index d40dd9414a..5ab49fa2b9 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -171,11 +171,6 @@ namespace osu.Game.Screens.Select Height = FilterControl.HEIGHT, FilterChanged = c => Carousel.Filter(c), Background = { Width = 2 }, - Exit = () => - { - if (this.IsCurrentScreen()) - this.Exit(); - }, }, } }, From ff6367fa4b113052fd835a05ff776049e3ca818f Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 1 Oct 2019 08:26:45 -0700 Subject: [PATCH 190/966] Make back button glow when pressing escape --- osu.Game/Graphics/UserInterface/BackButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index 62c33b9a39..23565e8742 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface public BackButton(Receptor receptor) { - receptor.OnBackPressed = () => Action?.Invoke(); + receptor.OnBackPressed = () => button.Click(); Size = TwoLayerButton.SIZE_EXTENDED; From e3502f52008e01e6de850ab7820332a9e6f2a694 Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 1 Oct 2019 08:37:08 -0700 Subject: [PATCH 191/966] Fix typo on Key.Escape comment --- osu.Game/Graphics/UserInterface/FocusedTextBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index 62fbb3592c..0b183c0ec9 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -61,7 +61,7 @@ namespace osu.Game.Graphics.UserInterface if (!HasFocus) return false; if (e.Key == Key.Escape) - return false; // disable the framework-level handling of escape key for confority (we use GlobalAction.Back). + return false; // disable the framework-level handling of escape key for conformity (we use GlobalAction.Back). return base.OnKeyDown(e); } From 2ac5e0bfa0b6961eb07e09f8995b5d041b449561 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 1 Oct 2019 17:39:01 +0200 Subject: [PATCH 192/966] Make use of SessionStatics --- osu.Game/Configuration/SessionStatics.cs | 2 ++ osu.Game/Screens/Play/PlayerLoader.cs | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 818a95c0be..40b2adb867 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -11,11 +11,13 @@ namespace osu.Game.Configuration protected override void InitialiseDefaults() { Set(Static.LoginOverlayDisplayed, false); + Set(Static.MutedAudioNotificationShownOnce, false); } } public enum Static { LoginOverlayDisplayed, + MutedAudioNotificationShownOnce } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 157ff8fcd4..635201879b 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -15,6 +16,7 @@ using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -71,8 +73,10 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader] - private void load() + private void load(SessionStatics sessionStatics) { + muteWarningShownOnce = sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce); + InternalChild = (content = new LogoTrackingContainer { Anchor = Anchor.Centre, @@ -157,18 +161,18 @@ namespace osu.Game.Screens.Play [Resolved] private AudioManager audioManager { get; set; } - private static bool muteWarningShownOnce; + private Bindable muteWarningShownOnce; private void checkVolume() { - if (muteWarningShownOnce) + if (muteWarningShownOnce.Value) return; //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) { notificationOverlay?.Post(new MutedNotification()); - muteWarningShownOnce = true; + muteWarningShownOnce.Value = true; } } From 5f399add82ece40b2f927982f0762d1d86369c04 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 1 Oct 2019 18:15:40 +0200 Subject: [PATCH 193/966] Resolve @iiSaLMaN 's suggested changes --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 6 +++++- osu.Game/Screens/Play/PlayerLoader.cs | 8 -------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 6866fd4c62..74ae641bfe 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; using osu.Framework.Screens; +using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -36,6 +37,9 @@ namespace osu.Game.Tests.Visual.Gameplay [Resolved] private AudioManager audioManager { get; set; } + [Resolved] + private SessionStatics sessionStatics { get; set; } + /// /// Sets the input manager child to a new test player loader container instance. /// @@ -137,7 +141,7 @@ namespace osu.Game.Tests.Visual.Gameplay /// The function to be invoked and checked private void addVolumeSteps(string volumeName, Action beforeLoad, Action afterLoad, Func assert) { - AddStep("reset notification lock", PlayerLoader.ResetNotificationLock); + AddStep("reset notification lock", () => sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).Value = false); AddStep("load player", () => ResetPlayer(false, beforeLoad, afterLoad)); AddUntilStep("wait for player", () => player.IsLoaded); diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 635201879b..7f8ef60a5d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -536,13 +536,5 @@ namespace osu.Game.Screens.Play }; } } - - /// - /// Sets to false, reserved for testing. - /// - public static void ResetNotificationLock() - { - muteWarningShownOnce = false; - } } } From b6dd610af847b9d15c7a8fcb761110f7fd40c18f Mon Sep 17 00:00:00 2001 From: Ganendra Afrasya Date: Tue, 1 Oct 2019 23:18:03 +0700 Subject: [PATCH 194/966] Apply reviews --- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 2 +- osu.Game/Overlays/Chat/ChatLine.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 00defd5f34..6a94cec4fd 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -146,7 +146,7 @@ namespace osu.Game.Online.Chat protected override float HorizontalPadding => 10; protected override float MessagePadding => 120; - protected override float TimestampPadding => 130; + protected override float TimestampPadding => 50; public StandAloneMessage(Message message) : base(message) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 1f5f5d3ff6..db378bde73 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -96,7 +96,7 @@ namespace osu.Game.Overlays.Chat Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - MaxWidth = default_message_padding - TimestampPadding + MaxWidth = MessagePadding - TimestampPadding }; if (hasBackground) @@ -151,7 +151,6 @@ namespace osu.Game.Overlays.Chat new MessageSender(message.Sender) { AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = TimestampPadding }, Origin = Anchor.TopRight, Anchor = Anchor.TopRight, Child = effectedUsername, From faf8fe132ecc0fc9971406d25a09109088fa4b32 Mon Sep 17 00:00:00 2001 From: HDragonHR Date: Wed, 2 Oct 2019 12:26:46 +0800 Subject: [PATCH 195/966] Change bindable int to float --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Graphics/Containers/HoldToConfirmContainer.cs | 4 ++-- .../Settings/Sections/Graphics/UserInterfaceSettings.cs | 6 +++--- osu.Game/Screens/Menu/MainMenu.cs | 4 ++-- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 64b1f2d7bc..c0ce08ba08 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -114,7 +114,7 @@ namespace osu.Game.Configuration Set(OsuSetting.UIScale, 1f, 0.8f, 1.6f, 0.01f); - Set(OsuSetting.UIHoldActivationDelay, 200, 0, 500); + Set(OsuSetting.UIHoldActivationDelay, 200f, 0f, 500f, 50f); Set(OsuSetting.IntroSequence, IntroSequence.Triangles); } diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 5d549ba217..fcf445a878 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -30,12 +30,12 @@ namespace osu.Game.Graphics.Containers public Bindable Progress = new BindableDouble(); - private Bindable holdActivationDelay; + private Bindable holdActivationDelay; [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - holdActivationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + holdActivationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); } protected void BeginConfirm() diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs index a6956b7d9a..a8953ac3a2 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs @@ -27,16 +27,16 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics LabelText = "Parallax", Bindable = config.GetBindable(OsuSetting.MenuParallax) }, - new SettingsSlider + new SettingsSlider { LabelText = "Hold-to-confirm activation time", - Bindable = config.GetBindable(OsuSetting.UIHoldActivationDelay), + Bindable = config.GetBindable(OsuSetting.UIHoldActivationDelay), KeyboardStep = 50 }, }; } - private class TimeSlider : OsuSliderBar + private class TimeSlider : OsuSliderBar { public override string TooltipText => Current.Value.ToString("N0") + "ms"; } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 16e9d67cc3..c195ed6cb6 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Menu protected override BackgroundScreen CreateBackground() => background; - private Bindable holdDelay; + private Bindable holdDelay; private Bindable loginDisplayed; private ExitConfirmOverlay exitConfirmOverlay; @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Menu [BackgroundDependencyLoader(true)] private void load(DirectOverlay direct, SettingsOverlay settings, OsuConfigManager config, SessionStatics statics) { - holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); loginDisplayed = statics.GetBindable(Static.LoginOverlayDisplayed); if (host.CanExit) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 2dc50326a8..a05937801c 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -63,11 +63,11 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private OsuConfigManager config { get; set; } - private Bindable activationDelay; + private Bindable activationDelay; protected override void LoadComplete() { - activationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + activationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); activationDelay.BindValueChanged(v => { text.Text = v.NewValue > 0 From dfaa9531f8f4fc6470a5a4bb60bea87fc44eed76 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 2 Oct 2019 18:48:50 +0900 Subject: [PATCH 196/966] Only lock the database for the duration of a deletion --- osu.Game/Database/ArchiveModelManager.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 17d1bd822e..2cc1e016d1 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -400,20 +400,17 @@ namespace osu.Game.Database int i = 0; - using (ContextFactory.GetForWrite()) + foreach (var b in items) { - foreach (var b in items) - { - if (notification.State == ProgressNotificationState.Cancelled) - // user requested abort - return; + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; - notification.Text = $"Deleting {HumanisedModelName}s ({++i} of {items.Count})"; + notification.Text = $"Deleting {HumanisedModelName}s ({++i} of {items.Count})"; - Delete(b); + Delete(b); - notification.Progress = (float)i / items.Count; - } + notification.Progress = (float)i / items.Count; } notification.State = ProgressNotificationState.Completed; From 6929847b0870664c8f2568170cd08935cc876dd8 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 2 Oct 2019 17:22:34 +0200 Subject: [PATCH 197/966] Remove redundant override --- osu.Game/Screens/Play/PlayerLoader.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 7f8ef60a5d..cd4b331fce 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -516,8 +516,6 @@ namespace osu.Game.Screens.Play public override bool IsImportant => true; - public override bool RequestsFocus => true; - [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay) { From a69b9f1148bbee373e6243452291cbab0bab0e16 Mon Sep 17 00:00:00 2001 From: Joehu Date: Wed, 2 Oct 2019 11:16:31 -0700 Subject: [PATCH 198/966] Fix alt-f4 being blocked during gameplay --- osu.Game/Screens/Play/Player.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 44be73b089..91d34c8056 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -299,7 +299,10 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - this.Exit(); + if (canPause) + Pause(); + else + this.Exit(); } public void Restart() @@ -508,12 +511,6 @@ namespace osu.Game.Screens.Play return true; } - if (canPause) - { - Pause(); - return true; - } - // ValidForResume is false when restarting if (ValidForResume) { From 752dd26a4f5a73823a9acbcbc5b518f9a9b6f4bf Mon Sep 17 00:00:00 2001 From: Joehu Date: Wed, 2 Oct 2019 11:17:43 -0700 Subject: [PATCH 199/966] Fix alt-f4 being blocked in interface --- osu.Game/Screens/Menu/MainMenu.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index c195ed6cb6..df4803b2b6 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -81,8 +81,8 @@ namespace osu.Game.Screens.Menu { if (holdDelay.Value > 0) confirmAndExit(); - else - this.Exit(); + else if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) + dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); } }); } @@ -253,12 +253,6 @@ namespace osu.Game.Screens.Menu public override bool OnExiting(IScreen next) { - if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) - { - dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); - return true; - } - buttons.State = ButtonSystemState.Exit; this.FadeOut(3000); return base.OnExiting(next); From ff56453f1a259ed80d8ab6338ba4d8c9b93a27d3 Mon Sep 17 00:00:00 2001 From: Joehu Date: Wed, 2 Oct 2019 12:07:07 -0700 Subject: [PATCH 200/966] Fix test regressions --- osu.Game.Tests/Visual/Gameplay/TestScenePause.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 50583e43c4..c67001c3d8 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -132,9 +132,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("exit", () => Player.Exit()); - confirmPaused(); - - exitAndConfirm(); + confirmExited(); } [Test] From 38fe519c91f9836f46b6a9347e4ceb97a96f0d67 Mon Sep 17 00:00:00 2001 From: Joehu Date: Wed, 2 Oct 2019 12:28:48 -0700 Subject: [PATCH 201/966] Remove unnecessary exitConfirmed condition check --- osu.Game/Screens/Menu/MainMenu.cs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index df4803b2b6..6deb29c2f2 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -80,9 +80,9 @@ namespace osu.Game.Screens.Menu Action = () => { if (holdDelay.Value > 0) - confirmAndExit(); - else if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) - dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); + this.Exit(); + else if (dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) + dialogOverlay.Push(new ConfirmExitDialog(this.Exit, () => exitConfirmOverlay.Abort())); } }); } @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Menu OnEdit = delegate { this.Push(new Editor()); }, OnSolo = onSolo, OnMulti = delegate { this.Push(new Multiplayer()); }, - OnExit = confirmAndExit, + OnExit = this.Exit, } } }, @@ -129,12 +129,6 @@ namespace osu.Game.Screens.Menu preloadSongSelect(); } - private void confirmAndExit() - { - exitConfirmed = true; - this.Exit(); - } - private void preloadSongSelect() { if (songSelect == null) @@ -172,8 +166,6 @@ namespace osu.Game.Screens.Menu Beatmap.ValueChanged += beatmap_ValueChanged; } - private bool exitConfirmed; - protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); From 148089f160240fc408f5a68b72caa2b84dc8731e Mon Sep 17 00:00:00 2001 From: Joehu Date: Wed, 2 Oct 2019 16:08:19 -0700 Subject: [PATCH 202/966] Revert "Remove unnecessary exitConfirmed condition check" This reverts commit 38fe519c91f9836f46b6a9347e4ceb97a96f0d67. --- osu.Game/Screens/Menu/MainMenu.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 6deb29c2f2..df4803b2b6 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -80,9 +80,9 @@ namespace osu.Game.Screens.Menu Action = () => { if (holdDelay.Value > 0) - this.Exit(); - else if (dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) - dialogOverlay.Push(new ConfirmExitDialog(this.Exit, () => exitConfirmOverlay.Abort())); + confirmAndExit(); + else if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) + dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); } }); } @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Menu OnEdit = delegate { this.Push(new Editor()); }, OnSolo = onSolo, OnMulti = delegate { this.Push(new Multiplayer()); }, - OnExit = this.Exit, + OnExit = confirmAndExit, } } }, @@ -129,6 +129,12 @@ namespace osu.Game.Screens.Menu preloadSongSelect(); } + private void confirmAndExit() + { + exitConfirmed = true; + this.Exit(); + } + private void preloadSongSelect() { if (songSelect == null) @@ -166,6 +172,8 @@ namespace osu.Game.Screens.Menu Beatmap.ValueChanged += beatmap_ValueChanged; } + private bool exitConfirmed; + protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); From 80177885213d56d52f2386dc885784c0549a0db6 Mon Sep 17 00:00:00 2001 From: Joehu Date: Wed, 2 Oct 2019 16:08:24 -0700 Subject: [PATCH 203/966] Revert "Fix alt-f4 being blocked in interface" This reverts commit 752dd26a4f5a73823a9acbcbc5b518f9a9b6f4bf. --- osu.Game/Screens/Menu/MainMenu.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index df4803b2b6..c195ed6cb6 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -81,8 +81,8 @@ namespace osu.Game.Screens.Menu { if (holdDelay.Value > 0) confirmAndExit(); - else if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) - dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); + else + this.Exit(); } }); } @@ -253,6 +253,12 @@ namespace osu.Game.Screens.Menu public override bool OnExiting(IScreen next) { + if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) + { + dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); + return true; + } + buttons.State = ButtonSystemState.Exit; this.FadeOut(3000); return base.OnExiting(next); From f8eb07b21116e9ae3f01eba30cd626e50f097a32 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 11:23:21 +0900 Subject: [PATCH 204/966] Only lock database for the duration of a model restoration --- osu.Game/Database/ArchiveModelManager.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 2cc1e016d1..b567f0c0e3 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -436,20 +436,17 @@ namespace osu.Game.Database int i = 0; - using (ContextFactory.GetForWrite()) + foreach (var item in items) { - foreach (var item in items) - { - if (notification.State == ProgressNotificationState.Cancelled) - // user requested abort - return; + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; - notification.Text = $"Restoring ({++i} of {items.Count})"; + notification.Text = $"Restoring ({++i} of {items.Count})"; - Undelete(item); + Undelete(item); - notification.Progress = (float)i / items.Count; - } + notification.Progress = (float)i / items.Count; } notification.State = ProgressNotificationState.Completed; From 897b3233afdd196157db7891bc7ad05b8a173e0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 14:23:48 +0900 Subject: [PATCH 205/966] Add start time tracking to EditorBeatmap --- osu.Game/Rulesets/Objects/HitObject.cs | 20 ++++++++++++++++- osu.Game/Screens/Edit/EditorBeatmap.cs | 31 +++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 6c5627c5d2..a99fac09cc 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Newtonsoft.Json; +using osu.Framework.Bindables; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -27,10 +28,16 @@ namespace osu.Game.Rulesets.Objects /// private const double control_point_leniency = 1; + public readonly Bindable StartTimeBindable = new Bindable(); + /// /// The time at which the HitObject starts. /// - public virtual double StartTime { get; set; } + public virtual double StartTime + { + get => StartTimeBindable.Value; + set => StartTimeBindable.Value = value; + } private List samples; @@ -67,6 +74,17 @@ namespace osu.Game.Rulesets.Objects [JsonIgnore] public IReadOnlyList NestedHitObjects => nestedHitObjects; + public HitObject() + { + StartTimeBindable.ValueChanged += time => + { + double offset = time.NewValue - time.OldValue; + + foreach (var nested in NestedHitObjects) + nested.StartTime += offset; + }; + } + /// /// Applies default values to this HitObject. /// diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index f0b6c62154..22aa133de7 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Timing; @@ -15,12 +16,17 @@ namespace osu.Game.Screens.Edit { public event Action HitObjectAdded; public event Action HitObjectRemoved; + public event Action HitObjectChanged; + private readonly Dictionary> startTimeBindables = new Dictionary>(); private readonly Beatmap beatmap; public EditorBeatmap(Beatmap beatmap) { this.beatmap = beatmap; + + foreach (var obj in HitObjects) + trackStartTime(obj); } public BeatmapInfo BeatmapInfo @@ -37,7 +43,7 @@ namespace osu.Game.Screens.Edit public double TotalBreakTime => beatmap.TotalBreakTime; - IReadOnlyList IBeatmap.HitObjects => beatmap.HitObjects; + public IReadOnlyList HitObjects => beatmap.HitObjects; IReadOnlyList IBeatmap.HitObjects => beatmap.HitObjects; @@ -51,6 +57,8 @@ namespace osu.Game.Screens.Edit /// The to add. public void Add(T hitObject) { + trackStartTime(hitObject); + // Preserve existing sorting order in the beatmap var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); beatmap.HitObjects.Insert(insertionIndex + 1, hitObject); @@ -65,7 +73,28 @@ namespace osu.Game.Screens.Edit public void Remove(T hitObject) { if (beatmap.HitObjects.Remove(hitObject)) + { + var bindable = startTimeBindables[hitObject]; + bindable.UnbindAll(); + + startTimeBindables.Remove(hitObject); HitObjectRemoved?.Invoke(hitObject); + } + } + + private void trackStartTime(T hitObject) + { + startTimeBindables[hitObject] = hitObject.StartTimeBindable.GetBoundCopy(); + startTimeBindables[hitObject].ValueChanged += _ => + { + // For now we'll remove and re-add the hitobject. This is not optimal and can be improved if required. + beatmap.HitObjects.Remove(hitObject); + + var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); + beatmap.HitObjects.Insert(insertionIndex + 1, hitObject); + + HitObjectChanged?.Invoke(hitObject); + }; } /// From f2719afd0e7f7e445659e413e03edd32125db3f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 14:27:40 +0900 Subject: [PATCH 206/966] Add tests for Editorbeatmap --- osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs | 154 +++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs diff --git a/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs b/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs new file mode 100644 index 0000000000..88c9f9cb6c --- /dev/null +++ b/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs @@ -0,0 +1,154 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using Microsoft.EntityFrameworkCore.Internal; +using NUnit.Framework; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit; + +namespace osu.Game.Tests.Beatmaps +{ + [TestFixture] + public class EditorBeatmapTest + { + /// + /// Tests that the addition event is correctly invoked after a hitobject is added. + /// + [Test] + public void TestHitObjectAddEvent() + { + var editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + + HitObject addedObject = null; + editorBeatmap.HitObjectAdded += h => addedObject = h; + + var hitCircle = new HitCircle(); + + editorBeatmap.Add(hitCircle); + Assert.That(addedObject, Is.EqualTo(hitCircle)); + } + + /// + /// Tests that the removal event is correctly invoked after a hitobject is removed. + /// + [Test] + public void HitObjectRemoveEvent() + { + var hitCircle = new HitCircle(); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); + + HitObject removedObject = null; + editorBeatmap.HitObjectRemoved += h => removedObject = h; + + editorBeatmap.Remove(hitCircle); + Assert.That(removedObject, Is.EqualTo(hitCircle)); + } + + /// + /// Tests that the changed event is correctly invoked after the start time of a hitobject is changed. + /// This tests for hitobjects which were already present before the editor beatmap was constructed. + /// + [Test] + public void TestInitialHitObjectStartTimeChangeEvent() + { + var hitCircle = new HitCircle(); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); + + HitObject changedObject = null; + editorBeatmap.HitObjectChanged += h => changedObject = h; + + hitCircle.StartTime = 1000; + Assert.That(changedObject, Is.EqualTo(hitCircle)); + } + + /// + /// Tests that the changed event is correctly invoked after the start time of a hitobject is changed. + /// This tests for hitobjects which were added to an existing editor beatmap. + /// + [Test] + public void TestAddedHitObjectStartTimeChangeEvent() + { + var editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + + HitObject changedObject = null; + editorBeatmap.HitObjectChanged += h => changedObject = h; + + var hitCircle = new HitCircle(); + + editorBeatmap.Add(hitCircle); + Assert.That(changedObject, Is.Null); + + hitCircle.StartTime = 1000; + Assert.That(changedObject, Is.EqualTo(hitCircle)); + } + + /// + /// Tests that the channged event is not invoked after a hitobject is removed from the beatmap/ + /// + [Test] + public void TestRemovedHitObjectStartTimeChangeEvent() + { + var hitCircle = new HitCircle(); + var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); + + HitObject changedObject = null; + editorBeatmap.HitObjectChanged += h => changedObject = h; + + editorBeatmap.Remove(hitCircle); + Assert.That(changedObject, Is.Null); + + hitCircle.StartTime = 1000; + Assert.That(changedObject, Is.Null); + } + + /// + /// Tests that an added hitobject is correctly inserted to preserve the sorting order of the beatmap. + /// + [Test] + public void TestAddHitObjectInMiddle() + { + var editorBeatmap = new EditorBeatmap(new OsuBeatmap + { + HitObjects = + { + new HitCircle(), + new HitCircle { StartTime = 1000 }, + new HitCircle { StartTime = 1000 }, + new HitCircle { StartTime = 2000 }, + } + }); + + var hitCircle = new HitCircle { StartTime = 1000 }; + editorBeatmap.Add(hitCircle); + Assert.That(editorBeatmap.HitObjects.Count(h => h == hitCircle), Is.EqualTo(1)); + Assert.That(editorBeatmap.HitObjects.IndexOf(hitCircle), Is.EqualTo(3)); + } + + /// + /// Tests that the beatmap remains correctly sorted after the start time of a hitobject is changed. + /// + [Test] + public void TestResortWhenStartTimeChanged() + { + var hitCircle = new HitCircle { StartTime = 1000 }; + var editorBeatmap = new EditorBeatmap(new OsuBeatmap + { + HitObjects = + { + new HitCircle(), + new HitCircle { StartTime = 1000 }, + new HitCircle { StartTime = 1000 }, + hitCircle, + new HitCircle { StartTime = 2000 }, + } + }); + + hitCircle.StartTime = 0; + Assert.That(editorBeatmap.HitObjects.Count(h => h == hitCircle), Is.EqualTo(1)); + Assert.That(editorBeatmap.HitObjects.IndexOf(hitCircle), Is.EqualTo(1)); + } + } +} From 3fb0b0b66833d107ef2e5e17f9930959deefeff2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 14:37:16 +0900 Subject: [PATCH 207/966] Rename to StartTimeChanged and add xmldocs --- osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs | 6 +++--- osu.Game/Screens/Edit/EditorBeatmap.cs | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs b/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs index 88c9f9cb6c..98e630abd2 100644 --- a/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/EditorBeatmapTest.cs @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); HitObject changedObject = null; - editorBeatmap.HitObjectChanged += h => changedObject = h; + editorBeatmap.StartTimeChanged += h => changedObject = h; hitCircle.StartTime = 1000; Assert.That(changedObject, Is.EqualTo(hitCircle)); @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Beatmaps var editorBeatmap = new EditorBeatmap(new OsuBeatmap()); HitObject changedObject = null; - editorBeatmap.HitObjectChanged += h => changedObject = h; + editorBeatmap.StartTimeChanged += h => changedObject = h; var hitCircle = new HitCircle(); @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps var editorBeatmap = new EditorBeatmap(new OsuBeatmap { HitObjects = { hitCircle } }); HitObject changedObject = null; - editorBeatmap.HitObjectChanged += h => changedObject = h; + editorBeatmap.StartTimeChanged += h => changedObject = h; editorBeatmap.Remove(hitCircle); Assert.That(changedObject, Is.Null); diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 22aa133de7..c3a322ea36 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -14,9 +14,20 @@ namespace osu.Game.Screens.Edit public class EditorBeatmap : IEditorBeatmap where T : HitObject { + /// + /// Invoked when a is added to this . + /// public event Action HitObjectAdded; + + /// + /// Invoked when a is removed from this . + /// public event Action HitObjectRemoved; - public event Action HitObjectChanged; + + /// + /// Invoked when the start time of a in this was changed. + /// + public event Action StartTimeChanged; private readonly Dictionary> startTimeBindables = new Dictionary>(); private readonly Beatmap beatmap; @@ -93,7 +104,7 @@ namespace osu.Game.Screens.Edit var insertionIndex = beatmap.HitObjects.FindLastIndex(h => h.StartTime <= hitObject.StartTime); beatmap.HitObjects.Insert(insertionIndex + 1, hitObject); - HitObjectChanged?.Invoke(hitObject); + StartTimeChanged?.Invoke(hitObject); }; } From 2c13043c42b79fb166483862284fce652f3fb17f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 14:40:00 +0900 Subject: [PATCH 208/966] Hook up the event to HitObjectComposer --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index fc324d7021..a267d7c44d 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -132,6 +132,7 @@ namespace osu.Game.Rulesets.Edit editorBeatmap = new EditorBeatmap(playableBeatmap); editorBeatmap.HitObjectAdded += addHitObject; editorBeatmap.HitObjectRemoved += removeHitObject; + editorBeatmap.StartTimeChanged += updateHitObject; var dependencies = new DependencyContainer(parent); dependencies.CacheAs(editorBeatmap); @@ -162,12 +163,7 @@ namespace osu.Game.Rulesets.Edit }); } - private void addHitObject(HitObject hitObject) - { - beatmapProcessor?.PreProcess(); - hitObject.ApplyDefaults(playableBeatmap.ControlPointInfo, playableBeatmap.BeatmapInfo.BaseDifficulty); - beatmapProcessor?.PostProcess(); - } + private void addHitObject(HitObject hitObject) => updateHitObject(hitObject); private void removeHitObject(HitObject hitObject) { @@ -175,6 +171,13 @@ namespace osu.Game.Rulesets.Edit beatmapProcessor?.PostProcess(); } + private void updateHitObject(HitObject hitObject) + { + beatmapProcessor?.PreProcess(); + hitObject.ApplyDefaults(playableBeatmap.ControlPointInfo, playableBeatmap.BeatmapInfo.BaseDifficulty); + beatmapProcessor?.PostProcess(); + } + public override IEnumerable HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects; public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position); From b28689c774c8a0e4bc029eda00cb5a4083ad040e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Oct 2019 15:00:47 +0800 Subject: [PATCH 209/966] Fix key counters appearing negative on intense beatmaps When `FrameStabilityContainer` decides it needs multiple updates on the same frame, it ends up with an elapsed time of zero. This was interacting badly with the condition used in `RulesetInputManager` to govern playback direction. I have changed this to use `Rate` as exposed by the frame stable clock. - Closes #6198. --- .../Rulesets/UI/FrameStabilityContainer.cs | 28 ++++++++++--------- osu.Game/Rulesets/UI/RulesetInputManager.cs | 4 +-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 05d3c02381..74d3439c59 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -47,6 +47,11 @@ namespace osu.Game.Rulesets.UI private IFrameBasedClock parentGameplayClock; + /// + /// The current direction of playback to be exposed to frame stable children. + /// + private int direction; + [BackgroundDependencyLoader(true)] private void load(GameplayClock clock) { @@ -111,16 +116,12 @@ namespace osu.Game.Rulesets.UI validState = true; - manualClock.Rate = parentGameplayClock.Rate; - manualClock.IsRunning = parentGameplayClock.IsRunning; - var newProposedTime = parentGameplayClock.CurrentTime; try { if (!FrameStablePlayback) { - manualClock.CurrentTime = newProposedTime; requireMoreUpdateLoops = false; return; } @@ -128,9 +129,9 @@ namespace osu.Game.Rulesets.UI { // On the first update, frame-stability seeking would result in unexpected/unwanted behaviour. // Instead we perform an initial seek to the proposed time. - manualClock.CurrentTime = newProposedTime; - // do a second process to clear out ElapsedTime + // process frame (in addition to finally clause) to clear out ElapsedTime + manualClock.CurrentTime = newProposedTime; framedClock.ProcessFrame(); firstConsumption = false; @@ -144,11 +145,7 @@ namespace osu.Game.Rulesets.UI : Math.Max(newProposedTime, manualClock.CurrentTime - sixty_frame_time); } - if (!isAttached) - { - manualClock.CurrentTime = newProposedTime; - } - else + if (isAttached) { double? newTime = ReplayInputHandler.SetFrameFromTime(newProposedTime); @@ -156,9 +153,7 @@ namespace osu.Game.Rulesets.UI { // we shouldn't execute for this time value. probably waiting on more replay data. validState = false; - requireMoreUpdateLoops = true; - manualClock.CurrentTime = newProposedTime; return; } @@ -169,6 +164,13 @@ namespace osu.Game.Rulesets.UI } finally { + if (newProposedTime != manualClock.CurrentTime) + direction = newProposedTime > manualClock.CurrentTime ? 1 : -1; + + manualClock.CurrentTime = newProposedTime; + manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; + manualClock.IsRunning = parentGameplayClock.IsRunning; + // The manual clock time has changed in the above code. The framed clock now needs to be updated // to ensure that the its time is valid for our children before input is processed framedClock.ProcessFrame(); diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 98e27240d3..5cc213be41 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.UI { } - public bool OnPressed(T action) => Target.Children.OfType>().Any(c => c.OnPressed(action, Clock.ElapsedFrameTime > 0)); + public bool OnPressed(T action) => Target.Children.OfType>().Any(c => c.OnPressed(action, Clock.Rate >= 0)); - public bool OnReleased(T action) => Target.Children.OfType>().Any(c => c.OnReleased(action, Clock.ElapsedFrameTime > 0)); + public bool OnReleased(T action) => Target.Children.OfType>().Any(c => c.OnReleased(action, Clock.Rate >= 0)); } #endregion From 652acac87fa69d2debfd9ee18872e08379c4ad0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 16:14:42 +0900 Subject: [PATCH 210/966] Move placement movement event to BlueprintContainer --- .../Blueprints/HoldNotePlacementBlueprint.cs | 11 ++++------ .../Blueprints/ManiaPlacementBlueprint.cs | 9 ++++---- .../HitCircles/HitCirclePlacementBlueprint.cs | 13 ++--------- .../Sliders/SliderPlacementBlueprint.cs | 20 +++++------------ .../Spinners/SpinnerPlacementBlueprint.cs | 5 +++++ osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 8 ++++++- .../Compose/Components/BlueprintContainer.cs | 22 ++++++++++++++++++- 7 files changed, 48 insertions(+), 40 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs index 26115311f7..bcbc1ee527 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Graphics; -using osu.Framework.Input.Events; using osu.Game.Rulesets.Mania.Edit.Blueprints.Components; using osu.Game.Rulesets.Mania.Objects; using osuTK; @@ -49,13 +48,13 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints private double originalStartTime; - protected override bool OnMouseMove(MouseMoveEvent e) + public override void UpdatePosition(Vector2 screenSpacePosition) { - base.OnMouseMove(e); + base.UpdatePosition(screenSpacePosition); if (PlacementBegun) { - var endTime = TimeAt(e.ScreenSpaceMousePosition); + var endTime = TimeAt(screenSpacePosition); HitObject.StartTime = endTime < originalStartTime ? endTime : originalStartTime; HitObject.Duration = Math.Abs(endTime - originalStartTime); @@ -65,10 +64,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints headPiece.Width = tailPiece.Width = SnappedWidth; headPiece.X = tailPiece.X = SnappedMousePosition.X; - originalStartTime = HitObject.StartTime = TimeAt(e.ScreenSpaceMousePosition); + originalStartTime = HitObject.StartTime = TimeAt(screenSpacePosition); } - - return true; } } } diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index d3779e2e18..7ad38860dd 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -62,19 +62,18 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints return base.OnMouseUp(e); } - protected override bool OnMouseMove(MouseMoveEvent e) + public override void UpdatePosition(Vector2 screenSpacePosition) { if (!PlacementBegun) - Column = ColumnAt(e.ScreenSpaceMousePosition); + Column = ColumnAt(screenSpacePosition); - if (Column == null) return false; + if (Column == null) return; SnappedWidth = Column.DrawWidth; // Snap to the column var parentPos = Parent.ToLocalSpace(Column.ToScreenSpace(new Vector2(Column.DrawWidth / 2, 0))); - SnappedMousePosition = new Vector2(parentPos.X, e.MousePosition.Y); - return true; + SnappedMousePosition = new Vector2(parentPos.X, Parent.ToLocalSpace(screenSpacePosition).Y); } protected double TimeAt(Vector2 screenSpacePosition) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index a4050f0c31..0f6bee19bb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -19,14 +19,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles InternalChild = new HitCirclePiece(HitObject); } - protected override void LoadComplete() - { - base.LoadComplete(); - - // Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame - HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero; - } - protected override bool OnClick(ClickEvent e) { HitObject.StartTime = EditorClock.CurrentTime; @@ -34,10 +26,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles return true; } - protected override bool OnMouseMove(MouseMoveEvent e) + public override void UpdatePosition(Vector2 screenSpacePosition) { - HitObject.Position = e.MousePosition; - return true; + HitObject.Position = ToLocalSpace(screenSpacePosition); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 55de626d7d..62c879b05e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -47,28 +47,18 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders setState(PlacementState.Initial); } - protected override void LoadComplete() - { - base.LoadComplete(); - - // Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame - HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero; - } - - protected override bool OnMouseMove(MouseMoveEvent e) + public override void UpdatePosition(Vector2 screenSpacePosition) { switch (state) { case PlacementState.Initial: - HitObject.Position = e.MousePosition; - return true; + HitObject.Position = ToLocalSpace(screenSpacePosition); + break; case PlacementState.Body: - cursor = e.MousePosition - HitObject.Position; - return true; + cursor = ToLocalSpace(screenSpacePosition) - HitObject.Position; + break; } - - return false; } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 03d761c67f..730b8448de 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -7,6 +7,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; +using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { @@ -43,5 +44,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners return true; } + + public override void UpdatePosition(Vector2 screenSpacePosition) + { + } } } diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 757c269358..290fd8d27d 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -108,6 +108,12 @@ namespace osu.Game.Rulesets.Edit placementHandler.EndPlacement(HitObject); } + /// + /// Updates the position of this to a new screen-space position. + /// + /// The screen-space position. + public abstract void UpdatePosition(Vector2 screenSpacePosition); + /// /// Invokes , /// refreshing and parameters for the . @@ -125,7 +131,7 @@ namespace osu.Game.Rulesets.Edit case ScrollEvent _: return false; - case MouseEvent _: + case MouseButtonEvent _: return true; default: diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 7d25fd5283..d96d88c2b9 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; +using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; @@ -22,8 +23,8 @@ namespace osu.Game.Screens.Edit.Compose.Components private Container placementBlueprintContainer; private PlacementBlueprint currentPlacement; - private SelectionHandler selectionHandler; + private InputManager inputManager; private IEnumerable selections => selectionBlueprints.Children.Where(c => c.IsAlive); @@ -66,6 +67,8 @@ namespace osu.Game.Screens.Edit.Compose.Components beatmap.HitObjectAdded += addBlueprintFor; beatmap.HitObjectRemoved += removeBlueprintFor; + + inputManager = GetContainingInputManager(); } private HitObjectCompositionTool currentTool; @@ -136,6 +139,17 @@ namespace osu.Game.Screens.Edit.Compose.Components return true; } + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (currentPlacement != null) + { + currentPlacement.UpdatePosition(e.ScreenSpaceMousePosition); + return true; + } + + return base.OnMouseMove(e); + } + protected override void Update() { base.Update(); @@ -158,8 +172,14 @@ namespace osu.Game.Screens.Edit.Compose.Components currentPlacement = null; var blueprint = CurrentTool?.CreatePlacementBlueprint(); + if (blueprint != null) + { placementBlueprintContainer.Child = currentPlacement = blueprint; + + // Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame + blueprint.UpdatePosition(inputManager.CurrentState.Mouse.Position); + } } /// From f2ba87a1d2a2f66fa423a682a0eb2ef0f7edef9c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 16:28:56 +0900 Subject: [PATCH 211/966] Fix placement blueprint test scenes not working --- .../Visual/PlacementBlueprintTestScene.cs | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs index 2b177e264f..0688620b8e 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs @@ -4,6 +4,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; @@ -18,16 +20,17 @@ namespace osu.Game.Tests.Visual protected Container HitObjectContainer; private PlacementBlueprint currentBlueprint; + private InputManager inputManager; + protected PlacementBlueprintTestScene() { - Add(HitObjectContainer = CreateHitObjectContainer()); + Add(HitObjectContainer = CreateHitObjectContainer().With(c => c.Clock = new FramedClock(new StopwatchClock()))); } [BackgroundDependencyLoader] private void load() { Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2; - Add(currentBlueprint = CreateBlueprint()); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -38,6 +41,14 @@ namespace osu.Game.Tests.Visual return dependencies; } + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + Add(currentBlueprint = CreateBlueprint()); + } + public void BeginPlacement(HitObject hitObject) { } @@ -54,10 +65,27 @@ namespace osu.Game.Tests.Visual { } - protected virtual Container CreateHitObjectContainer() => new Container { RelativeSizeAxes = Axes.Both }; + protected override bool OnMouseMove(MouseMoveEvent e) + { + currentBlueprint.UpdatePosition(e.ScreenSpaceMousePosition); + return true; + } + + public override void Add(Drawable drawable) + { + base.Add(drawable); + + if (drawable is PlacementBlueprint blueprint) + { + blueprint.Show(); + blueprint.UpdatePosition(inputManager.CurrentState.Mouse.Position); + } + } protected virtual void AddHitObject(DrawableHitObject hitObject) => HitObjectContainer.Add(hitObject); + protected virtual Container CreateHitObjectContainer() => new Container { RelativeSizeAxes = Axes.Both }; + protected abstract DrawableHitObject CreateHitObject(HitObject hitObject); protected abstract PlacementBlueprint CreateBlueprint(); } From e9c73ce30fae825f2ed79150f3b4a098d346eb6c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Oct 2019 16:21:14 +0800 Subject: [PATCH 212/966] Fix random failures on BeatmapCarousel filter test The "un-filter" step causes a `SelectNextRandom` invocation. If this happens to select a difficulty in set 3 other than the previously buffered difficulty #2, the subsequent test would fail. I've split this test out to remove the random element, but added a new assert to ensure buffered (previously visited?) difficulty is re-selected on return to the same set. --- .../SongSelect/TestSceneBeatmapCarousel.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 90c6c9065c..6bdd94db21 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -239,6 +239,18 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selection is non-null", () => currentSelection != null); setSelected(1, 3); + } + + [Test] + public void TestFilterRange() + { + loadBeatmaps(); + + // buffer the selection + setSelected(3, 2); + + setSelected(1, 3); + AddStep("Apply a range filter", () => carousel.Filter(new FilterCriteria { SearchText = "#3", @@ -249,9 +261,9 @@ namespace osu.Game.Tests.Visual.SongSelect IsLowerInclusive = true } }, false)); - waitForSelection(3, 2); - AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false)); + // should reselect the buffered selection. + waitForSelection(3, 2); } /// From ee34c5ccb457e582868ced659a6d0f952cb98665 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:21:00 +0900 Subject: [PATCH 213/966] Add a flip step to mania placement test scenes --- .../ManiaPlacementBlueprintTestScene.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/ManiaPlacementBlueprintTestScene.cs index 4b3786c30a..afde1c9521 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaPlacementBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaPlacementBlueprintTestScene.cs @@ -27,8 +27,13 @@ namespace osu.Game.Rulesets.Mania.Tests [Cached(typeof(IReadOnlyList))] private IReadOnlyList mods { get; set; } = Array.Empty(); + [Cached(typeof(IScrollingInfo))] + private IScrollingInfo scrollingInfo; + protected ManiaPlacementBlueprintTestScene() { + scrollingInfo = ((ScrollingTestContainer)HitObjectContainer).ScrollingInfo; + Add(column = new Column(0) { Anchor = Anchor.Centre, @@ -36,15 +41,8 @@ namespace osu.Game.Rulesets.Mania.Tests AccentColour = Color4.OrangeRed, Clock = new FramedClock(new StopwatchClock()), // No scroll }); - } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - dependencies.CacheAs(((ScrollingTestContainer)HitObjectContainer).ScrollingInfo); - - return dependencies; + AddStep("change direction", () => ((ScrollingTestContainer)HitObjectContainer).Flip()); } protected override Container CreateHitObjectContainer() => new ScrollingTestContainer(ScrollingDirection.Down) { RelativeSizeAxes = Axes.Both }; From 754fbc59e1a96f2dc7da030dce850a0cb5231e78 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:21:36 +0900 Subject: [PATCH 214/966] Fix note placement being offset --- .../Edit/Blueprints/ManiaPlacementBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index d3779e2e18..f7d21ddf55 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints // If we're scrolling downwards, a position of 0 is actually further away from the hit target // so we need to flip the vertical coordinate in the hitobject container's space - var hitObjectPos = Column.HitObjectContainer.ToLocalSpace(applyPositionOffset(screenSpacePosition, false)).Y; + var hitObjectPos = applyPositionOffset(Column.HitObjectContainer.ToLocalSpace(screenSpacePosition), false).Y; if (scrollingInfo.Direction.Value == ScrollingDirection.Down) hitObjectPos = hitObjectContainer.DrawHeight - hitObjectPos; From 0a409075be251fbc1acbebfdfa80f81204d8f0a6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:21:50 +0900 Subject: [PATCH 215/966] Fix note placement offset not working for down-scroll --- .../Blueprints/ManiaPlacementBlueprint.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index f7d21ddf55..83282f9990 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -111,8 +111,23 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints private Vector2 applyPositionOffset(Vector2 position, bool reverse) { - position.Y += (scrollingInfo.Direction.Value == ScrollingDirection.Up && !reverse ? -1 : 1) * NotePiece.NOTE_HEIGHT / 2; - return position; + float offset = 0; + + switch (scrollingInfo.Direction.Value) + { + case ScrollingDirection.Up: + offset = -NotePiece.NOTE_HEIGHT / 2; + break; + + case ScrollingDirection.Down: + offset = NotePiece.NOTE_HEIGHT / 2; + break; + } + + if (reverse) + offset = -offset; + + return new Vector2(position.X, position.Y + offset); } } } From 39369620fa530000cf22dc6b1643b932b738dda1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:22:06 +0900 Subject: [PATCH 216/966] Remove position offset from ColumnAt --- .../Edit/Blueprints/ManiaPlacementBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index 83282f9990..a0feecee3b 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints } protected Column ColumnAt(Vector2 screenSpacePosition) - => composer.ColumnAt(applyPositionOffset(screenSpacePosition, false)); + => composer.ColumnAt(screenSpacePosition); private Vector2 applyPositionOffset(Vector2 position, bool reverse) { From f1ff22cf8bc1612aef947df2bdafd4e0e0d2cafd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:23:13 +0900 Subject: [PATCH 217/966] Fix hold note blueprint placing in the wrong direction --- .../Edit/Blueprints/ManiaPlacementBlueprint.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index a0feecee3b..4a187b1942 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -103,6 +103,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints scrollingInfo.TimeRange.Value, Column.HitObjectContainer.DrawHeight); + if (scrollingInfo.Direction.Value == ScrollingDirection.Down) + pos = Column.HitObjectContainer.DrawHeight - pos; + return applyPositionOffset(Column.HitObjectContainer.ToSpaceOfOtherDrawable(new Vector2(0, pos), Parent), true).Y; } From 80585d446c108268e3261933caf9ef2f3d56f1c6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:27:39 +0900 Subject: [PATCH 218/966] Split applyPositionOffset into two methods and add xmldocs --- .../Blueprints/ManiaPlacementBlueprint.cs | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index 4a187b1942..e83c85b40e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints // If we're scrolling downwards, a position of 0 is actually further away from the hit target // so we need to flip the vertical coordinate in the hitobject container's space - var hitObjectPos = applyPositionOffset(Column.HitObjectContainer.ToLocalSpace(screenSpacePosition), false).Y; + var hitObjectPos = mouseToHitObjectPosition(Column.HitObjectContainer.ToLocalSpace(screenSpacePosition)).Y; if (scrollingInfo.Direction.Value == ScrollingDirection.Down) hitObjectPos = hitObjectContainer.DrawHeight - hitObjectPos; @@ -106,31 +106,55 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints if (scrollingInfo.Direction.Value == ScrollingDirection.Down) pos = Column.HitObjectContainer.DrawHeight - pos; - return applyPositionOffset(Column.HitObjectContainer.ToSpaceOfOtherDrawable(new Vector2(0, pos), Parent), true).Y; + return hitObjectToMousePosition(Column.HitObjectContainer.ToSpaceOfOtherDrawable(new Vector2(0, pos), Parent)).Y; } protected Column ColumnAt(Vector2 screenSpacePosition) => composer.ColumnAt(screenSpacePosition); - private Vector2 applyPositionOffset(Vector2 position, bool reverse) + /// + /// Converts a mouse position to a hitobject position. + /// + /// + /// Blueprints are centred on the mouse position, such that the hitobject position is anchored at the top or bottom of the blueprint depending on the scroll direction. + /// + /// The mouse position. + /// The resulting hitobject position, acnhored at the top or bottom of the blueprint depending on the scroll direction. + private Vector2 mouseToHitObjectPosition(Vector2 mousePosition) { - float offset = 0; - switch (scrollingInfo.Direction.Value) { case ScrollingDirection.Up: - offset = -NotePiece.NOTE_HEIGHT / 2; + mousePosition.Y -= NotePiece.NOTE_HEIGHT / 2; break; case ScrollingDirection.Down: - offset = NotePiece.NOTE_HEIGHT / 2; + mousePosition.Y += NotePiece.NOTE_HEIGHT / 2; break; } - if (reverse) - offset = -offset; + return mousePosition; + } - return new Vector2(position.X, position.Y + offset); + /// + /// Converts a hitobject position to a mouse position. + /// + /// The hitobject position. + /// The resulting mouse position, anchored at the centre of the hitobject. + private Vector2 hitObjectToMousePosition(Vector2 hitObjectPosition) + { + switch (scrollingInfo.Direction.Value) + { + case ScrollingDirection.Up: + hitObjectPosition.Y += NotePiece.NOTE_HEIGHT / 2; + break; + + case ScrollingDirection.Down: + hitObjectPosition.Y -= NotePiece.NOTE_HEIGHT / 2; + break; + } + + return hitObjectPosition; } } } From 2d0c52239893526a28be0e01eacf74b18bab0ee3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:43:46 +0900 Subject: [PATCH 219/966] Remove unused method --- .../TestSceneHoldNoteSelectionBlueprint.cs | 3 --- .../TestSceneNoteSelectionBlueprint.cs | 3 --- .../TestSceneHitCircleSelectionBlueprint.cs | 3 --- .../TestSceneSliderSelectionBlueprint.cs | 3 --- .../TestSceneSpinnerSelectionBlueprint.cs | 3 --- osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs | 2 -- 6 files changed, 17 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs index 5507ca2ba0..90394f3d1b 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -53,7 +52,5 @@ namespace osu.Game.Rulesets.Mania.Tests nested.Y = (float)(-finalPosition * content.DrawHeight); } } - - protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs index c0482e2150..1514bdf0bd 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs @@ -5,7 +5,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -37,7 +36,5 @@ namespace osu.Game.Rulesets.Mania.Tests AddBlueprint(new NoteSelectionBlueprint(drawableObject)); } - - protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs index 7278d923c1..d4cdabdb07 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs @@ -4,7 +4,6 @@ using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; @@ -53,8 +52,6 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); } - protected override SelectionBlueprint CreateBlueprint() => new HitCircleSelectionBlueprint(drawableObject); - private class TestBlueprint : HitCircleSelectionBlueprint { public new HitCirclePiece CirclePiece => base.CirclePiece; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs index 61c8316ed9..ec23ec31b2 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs @@ -7,7 +7,6 @@ using NUnit.Framework; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; @@ -98,8 +97,6 @@ namespace osu.Game.Rulesets.Osu.Tests () => Precision.AlmostEquals(blueprint.TailBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.TailCircle.ScreenSpaceDrawQuad.Centre)); } - protected override SelectionBlueprint CreateBlueprint() => new SliderSelectionBlueprint(drawableObject); - private class TestSliderBlueprint : SliderSelectionBlueprint { public new SliderBodyPiece BodyPiece => base.BodyPiece; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs index 1c195311a4..d777ca3610 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; @@ -47,7 +46,5 @@ namespace osu.Game.Rulesets.Osu.Tests AddBlueprint(new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }); } - - protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(null) { Size = new Vector2(0.5f) }; } } diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index 55dda03b16..f53c12b047 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -30,7 +30,5 @@ namespace osu.Game.Tests.Visual d.Select(); })); } - - protected abstract SelectionBlueprint CreateBlueprint(); } } From bcf0b2752e75f40b046e6447cbfce2b705dfb0ce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:48:44 +0900 Subject: [PATCH 220/966] Fix possible MusicController nullref --- osu.Game/Overlays/MusicController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 49d16a4f3e..51afac4b8c 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -75,7 +75,7 @@ namespace osu.Game.Overlays /// /// Returns whether the current beatmap track is playing. /// - public bool IsPlaying => beatmap.Value?.Track.IsRunning ?? false; + public bool IsPlaying => beatmap?.Value?.Track.IsRunning ?? false; private void handleBeatmapAdded(BeatmapSetInfo set) => Schedule(() => beatmapSets.Add(set)); From 662a1a9c2cb8af2b6e151a9b1bed43d32491ca3b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:55:53 +0900 Subject: [PATCH 221/966] Use current --- osu.Game/Overlays/MusicController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 51afac4b8c..f5c36a9cac 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -75,7 +75,7 @@ namespace osu.Game.Overlays /// /// Returns whether the current beatmap track is playing. /// - public bool IsPlaying => beatmap?.Value?.Track.IsRunning ?? false; + public bool IsPlaying => current?.Track.IsRunning ?? false; private void handleBeatmapAdded(BeatmapSetInfo set) => Schedule(() => beatmapSets.Add(set)); From 6c878cb167544addc3a6af83efad12558a7b230d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 19:11:50 +0900 Subject: [PATCH 222/966] Prevent nullrefs --- osu.Game/Overlays/VolumeOverlay.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 0c08e0eb6e..27e2eef200 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -32,7 +32,8 @@ namespace osu.Game.Overlays private readonly BindableDouble muteAdjustment = new BindableDouble(); - public Bindable IsMuted => muteButton.Current; + private readonly Bindable isMuted = new Bindable(); + public Bindable IsMuted => isMuted; [BackgroundDependencyLoader] private void load(AudioManager audio, OsuColour colours) @@ -66,7 +67,8 @@ namespace osu.Game.Overlays volumeMeterMusic = new VolumeMeter("MUSIC", 125, colours.BlueDarker), muteButton = new MuteButton { - Margin = new MarginPadding { Top = 100 } + Margin = new MarginPadding { Top = 100 }, + Current = { BindTarget = isMuted } } } }, @@ -76,13 +78,13 @@ namespace osu.Game.Overlays volumeMeterEffect.Bindable.BindTo(audio.VolumeSample); volumeMeterMusic.Bindable.BindTo(audio.VolumeTrack); - muteButton.Current.ValueChanged += muted => + isMuted.BindValueChanged(muted => { if (muted.NewValue) audio.AddAdjustment(AdjustableProperty.Volume, muteAdjustment); else audio.RemoveAdjustment(AdjustableProperty.Volume, muteAdjustment); - }; + }); } protected override void LoadComplete() From 636913a4a6a62319f23f3b17f52552bfa3905409 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 19:16:31 +0900 Subject: [PATCH 223/966] Refactor PlayerLoader changes --- osu.Game/Screens/Play/PlayerLoader.cs | 63 ++++++++++++--------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index cd4b331fce..87d902b547 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -58,9 +58,19 @@ namespace osu.Game.Screens.Play private Task loadTask; private InputManager inputManager; - private IdleTracker idleTracker; + [Resolved(CanBeNull = true)] + private NotificationOverlay notificationOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private VolumeOverlay volumeOverlay { get; set; } + + [Resolved] + private AudioManager audioManager { get; set; } + + private Bindable muteWarningShownOnce; + public PlayerLoader(Func createPlayer) { this.createPlayer = createPlayer; @@ -110,7 +120,22 @@ namespace osu.Game.Screens.Play loadNewPlayer(); } - private void playerLoaded(Player player) => info.Loading = false; + protected override void LoadComplete() + { + base.LoadComplete(); + + inputManager = GetContainingInputManager(); + + if (!muteWarningShownOnce.Value) + { + //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. + if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) + { + notificationOverlay?.Post(new MutedNotification()); + muteWarningShownOnce.Value = true; + } + } + } public override void OnResuming(IScreen last) { @@ -134,7 +159,7 @@ namespace osu.Game.Screens.Play player.RestartCount = restartCount; player.RestartRequested = restartRequested; - loadTask = LoadComponentAsync(player, playerLoaded); + loadTask = LoadComponentAsync(player, _ => info.Loading = false); } private void contentIn() @@ -152,30 +177,6 @@ namespace osu.Game.Screens.Play content.FadeOut(250); } - [Resolved(CanBeNull = true)] - private NotificationOverlay notificationOverlay { get; set; } - - [Resolved(CanBeNull = true)] - private VolumeOverlay volumeOverlay { get; set; } - - [Resolved] - private AudioManager audioManager { get; set; } - - private Bindable muteWarningShownOnce; - - private void checkVolume() - { - if (muteWarningShownOnce.Value) - return; - - //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) - { - notificationOverlay?.Post(new MutedNotification()); - muteWarningShownOnce.Value = true; - } - } - public override void OnEntering(IScreen last) { base.OnEntering(last); @@ -216,14 +217,6 @@ namespace osu.Game.Screens.Play content.StopTracking(); } - protected override void LoadComplete() - { - inputManager = GetContainingInputManager(); - base.LoadComplete(); - - checkVolume(); - } - private ScheduledDelegate pushDebounce; protected VisualSettings VisualSettings; From d2c9a29c0d4bf8f805dbead933156a57ea466d75 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 10:45:18 +0800 Subject: [PATCH 224/966] Remove unnecessary local assign --- osu.Game/Screens/Select/SongSelect.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 5ab49fa2b9..e97fac96c5 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -66,11 +66,7 @@ namespace osu.Game.Screens.Select /// protected readonly Container FooterPanels; - protected override BackgroundScreen CreateBackground() - { - var background = new BackgroundScreenBeatmap(); - return background; - } + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(); protected readonly BeatmapCarousel Carousel; private readonly BeatmapInfoWedge beatmapInfoWedge; From 925615320e4d8ae455738b5dc3fa1de8a170f71f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 10:46:48 +0800 Subject: [PATCH 225/966] Update lazer default combo colours to match stable --- osu.Game/Skinning/DefaultSkinConfiguration.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/DefaultSkinConfiguration.cs b/osu.Game/Skinning/DefaultSkinConfiguration.cs index f52fac6077..cd5975edac 100644 --- a/osu.Game/Skinning/DefaultSkinConfiguration.cs +++ b/osu.Game/Skinning/DefaultSkinConfiguration.cs @@ -14,10 +14,10 @@ namespace osu.Game.Skinning { ComboColours.AddRange(new[] { - new Color4(17, 136, 170, 255), - new Color4(102, 136, 0, 255), - new Color4(204, 102, 0, 255), - new Color4(121, 9, 13, 255) + new Color4(255, 192, 0, 255), + new Color4(0, 202, 0, 255), + new Color4(18, 124, 255, 255), + new Color4(242, 24, 57, 255), }); } } From 71985c7ef13913af2d3c6acf07c17ac4d11986c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 11:23:42 +0800 Subject: [PATCH 226/966] Update fail logic to match --- osu.Game/Screens/Play/Player.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 91d34c8056..5560baa7d1 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -299,6 +299,12 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; + if (HasFailed && !FailOverlay.IsPresent) + { + failAnimation.FinishTransforms(true); + return; + } + if (canPause) Pause(); else @@ -517,12 +523,6 @@ namespace osu.Game.Screens.Play if (pauseCooldownActive && !GameplayClockContainer.IsPaused.Value) // still want to block if we are within the cooldown period and not already paused. return true; - - if (HasFailed && !FailOverlay.IsPresent) - { - failAnimation.FinishTransforms(true); - return true; - } } GameplayClockContainer.ResetLocalAdjustments(); From e646b2677ca0b07267690783cf8894676e437dc4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 11:25:23 +0800 Subject: [PATCH 227/966] Add test coverage --- osu.Game.Tests/Visual/Gameplay/TestScenePause.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index c67001c3d8..48159aa5e0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -127,6 +127,15 @@ namespace osu.Game.Tests.Visual.Gameplay exitAndConfirm(); } + [Test] + public void TestExitFromFailedGameplay() + { + AddUntilStep("wait for fail", () => Player.HasFailed); + AddStep("exit", () => Player.Exit()); + + confirmExited(); + } + [Test] public void TestExitFromGameplay() { From 47c1f36f9d91f54eb68b824badad248b69c169be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 11:41:53 +0800 Subject: [PATCH 228/966] Add ValidForResume check --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5560baa7d1..0b363eac4d 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -299,7 +299,7 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - if (HasFailed && !FailOverlay.IsPresent) + if (ValidForResume && HasFailed && !FailOverlay.IsPresent) { failAnimation.FinishTransforms(true); return; From 626f7388c8fdc8dd34935d2a8cf86cfaf702ac4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 12:23:01 +0800 Subject: [PATCH 229/966] Add tests for quick retry and quick exit scenarios --- .../Visual/Gameplay/TestScenePause.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 48159aa5e0..2df22df659 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -136,6 +136,24 @@ namespace osu.Game.Tests.Visual.Gameplay confirmExited(); } + [Test] + public void TestQuickRetryFromFailedGameplay() + { + AddUntilStep("wait for fail", () => Player.HasFailed); + AddStep("quick retry", () => Player.GameplayClockContainer.OfType().First().Action?.Invoke()); + + confirmExited(); + } + + [Test] + public void TestQuickExitFromFailedGameplay() + { + AddUntilStep("wait for fail", () => Player.HasFailed); + AddStep("quick exit", () => Player.GameplayClockContainer.OfType().First().Action?.Invoke()); + + confirmExited(); + } + [Test] public void TestExitFromGameplay() { @@ -144,6 +162,14 @@ namespace osu.Game.Tests.Visual.Gameplay confirmExited(); } + [Test] + public void TestQuickExitFromGameplay() + { + AddStep("quick exit", () => Player.GameplayClockContainer.OfType().First().Action?.Invoke()); + + confirmExited(); + } + [Test] public void TestExitViaHoldToExit() { From ffde389641a15f0b0faceb8e1e900fa186509bda Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 4 Oct 2019 13:28:32 +0900 Subject: [PATCH 230/966] Add difficulty calculator beatmap decoder fallback --- .../Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs index 2c493254e0..238187bf8f 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -24,6 +24,7 @@ namespace osu.Game.Beatmaps.Formats public new static void Register() { AddDecoder(@"osu file format v", m => new LegacyDifficultyCalculatorBeatmapDecoder(int.Parse(m.Split('v').Last()))); + SetFallbackDecoder(() => new LegacyDifficultyCalculatorBeatmapDecoder()); } protected override TimingControlPoint CreateTimingControlPoint() From ddef7fa3ba67d47ff90d62446d7ed5bbf294c46d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 13:32:47 +0800 Subject: [PATCH 231/966] Repair behavioural change --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 74d3439c59..c6d812aee3 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -157,7 +157,7 @@ namespace osu.Game.Rulesets.UI return; } - manualClock.CurrentTime = newTime.Value; + newProposedTime = newTime.Value; } requireMoreUpdateLoops = manualClock.CurrentTime != parentGameplayClock.CurrentTime; From aeb62825cdb0c0727fca76b6ae21541133aeb1e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Oct 2019 13:42:06 +0800 Subject: [PATCH 232/966] Move out requireMoreUpdateLoops for better consistency --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index c6d812aee3..e569bb8459 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -115,17 +115,16 @@ namespace osu.Game.Rulesets.UI setClock(); // LoadComplete may not be run yet, but we still want the clock. validState = true; + requireMoreUpdateLoops = false; var newProposedTime = parentGameplayClock.CurrentTime; try { if (!FrameStablePlayback) - { - requireMoreUpdateLoops = false; return; - } - else if (firstConsumption) + + if (firstConsumption) { // On the first update, frame-stability seeking would result in unexpected/unwanted behaviour. // Instead we perform an initial seek to the proposed time. @@ -159,8 +158,6 @@ namespace osu.Game.Rulesets.UI newProposedTime = newTime.Value; } - - requireMoreUpdateLoops = manualClock.CurrentTime != parentGameplayClock.CurrentTime; } finally { @@ -171,6 +168,8 @@ namespace osu.Game.Rulesets.UI manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; manualClock.IsRunning = parentGameplayClock.IsRunning; + requireMoreUpdateLoops |= manualClock.CurrentTime != parentGameplayClock.CurrentTime; + // The manual clock time has changed in the above code. The framed clock now needs to be updated // to ensure that the its time is valid for our children before input is processed framedClock.ProcessFrame(); From 7b414092afd261c953fd9f51f9bdf93632021523 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:35:41 +0300 Subject: [PATCH 233/966] Implement beatmap ruleset selector --- .../BeatmapSet/BeatmapRulesetSelector.cs | 50 ++++++ .../BeatmapSet/BeatmapRulesetTabItem.cs | 148 ++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs create mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs new file mode 100644 index 0000000000..0847272e1f --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -0,0 +1,50 @@ +// 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; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osuTK; +using System.Linq; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class BeatmapRulesetSelector : RulesetSelector + { + private BeatmapSetInfo beatmapSet; + + public BeatmapSetInfo BeatmapSet + { + get => beatmapSet; + set + { + if (value == beatmapSet) + return; + + beatmapSet = value; + + foreach (BeatmapRulesetTabItem tab in TabContainer.TabItems) + tab.SetBeatmaps(beatmapSet?.Beatmaps.FindAll(b => b.Ruleset.Equals(tab.Value))); + + var firstRuleset = beatmapSet?.Beatmaps.OrderBy(b => b.Ruleset.ID).FirstOrDefault()?.Ruleset; + SelectTab(TabContainer.TabItems.FirstOrDefault(t => t.Value.Equals(firstRuleset))); + } + } + + public BeatmapRulesetSelector() + { + AutoSizeAxes = Axes.Both; + TabContainer.Spacing = new Vector2(10, 0); + } + + protected override TabItem CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value); + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + Direction = FillDirection.Horizontal, + AutoSizeAxes = Axes.Both, + }; + } +} diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs new file mode 100644 index 0000000000..19c9af13d5 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -0,0 +1,148 @@ +// 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.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; +using osuTK; +using osuTK.Graphics; +using System.Collections.Generic; +using System.Diagnostics; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class BeatmapRulesetTabItem : TabItem + { + private readonly OsuSpriteText name, count; + private readonly Box bar; + + public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree; + + public BeatmapRulesetTabItem(RulesetInfo value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Masking = true; + + FillFlowContainer nameContainer; + + Children = new Drawable[] + { + nameContainer = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Bottom = 7.5f }, + Spacing = new Vector2(2.5f), + Children = new Drawable[] + { + name = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = value.Name, + Font = OsuFont.Default.With(size: 18), + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.5f), + }, + count = new OsuSpriteText + { + Alpha = 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = 5f }, + Font = OsuFont.Default.With(weight: FontWeight.SemiBold), + } + } + } + } + }, + bar = new Box + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = 4f, + }, + new HoverClickSounds(), + }; + + Enabled.BindValueChanged(v => nameContainer.Alpha = v.NewValue ? 1f : 0.5f, true); + } + + [Resolved] + private OsuColour colour { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + count.Colour = colour.Gray9; + bar.Colour = colour.Blue; + + updateState(); + } + + public void SetBeatmaps(List beatmaps) + { + Trace.Assert(beatmaps?.TrueForAll(b => b.Ruleset.Equals(Value)) ?? true, "A beatmap has a ruleset not of this tab value"); + + count.Text = beatmaps?.Count.ToString(); + + var hasBeatmaps = (beatmaps?.Count ?? 0) > 0; + count.Alpha = hasBeatmaps ? 1f : 0f; + Enabled.Value = hasBeatmaps; + } + + private void updateState() + { + var isHoveredOrActive = IsHovered || Active.Value; + name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC; + bar.MoveToY(isHoveredOrActive ? 0f : bar.Height, 120); + + name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular); + } + + #region Hovering and activation logic + + protected override void OnActivated() => updateState(); + + protected override void OnDeactivated() => updateState(); + + protected override bool OnHover(HoverEvent e) + { + updateState(); + return false; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateState(); + } + + #endregion + } +} From edddbdb7845a250002ee5dd111750b3290a29401 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:37:09 +0300 Subject: [PATCH 234/966] Add tests for beatmap ruleset selector --- .../Online/TestSceneBeatmapRulesetSelector.cs | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs new file mode 100644 index 0000000000..1f8df438fb --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs @@ -0,0 +1,102 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Beatmaps; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Rulesets; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneBeatmapRulesetSelector : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(BeatmapRulesetSelector), + typeof(BeatmapRulesetTabItem), + }; + + private readonly TestRulesetSelector selector; + + public TestSceneBeatmapRulesetSelector() + { + Add(selector = new TestRulesetSelector()); + } + + [Resolved] + private RulesetStore rulesets { get; set; } + + [Test] + public void TestMultipleRulesetsBeatmapSet() + { + var enabledRulesets = rulesets.AvailableRulesets.Skip(1).Take(2); + + AddStep("load multiple rulesets beatmapset", () => + { + selector.BeatmapSet = new BeatmapSetInfo + { + Beatmaps = enabledRulesets.Select(r => new BeatmapInfo { Ruleset = r }).ToList() + }; + }); + + var tabItems = selector.TabContainer.TabItems; + AddAssert("other rulesets disabled", () => tabItems.Except(tabItems.Where(t => enabledRulesets.Any(r => r.Equals(t.Value)))).All(t => !t.Enabled.Value)); + AddAssert("left-most ruleset selected", () => tabItems.First(t => t.Enabled.Value).Active.Value); + } + + [Test] + public void TestSingleRulesetBeatmapSet() + { + var enabledRuleset = rulesets.AvailableRulesets.Last(); + + AddStep("load single ruleset beatmapset", () => + { + selector.BeatmapSet = new BeatmapSetInfo + { + Beatmaps = new List + { + new BeatmapInfo + { + Ruleset = enabledRuleset + } + } + }; + }); + + AddAssert("single ruleset selected", () => selector.SelectedTab.Value.Equals(enabledRuleset)); + } + + [Test] + public void TestEmptyBeatmapSet() + { + AddStep("load empty beatmapset", () => selector.BeatmapSet = new BeatmapSetInfo + { + Beatmaps = new List() + }); + + AddAssert("no ruleset selected", () => selector.SelectedTab == null); + AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value)); + } + + [Test] + public void TestNullBeatmapSet() + { + AddStep("load null beatmapset", () => selector.BeatmapSet = null); + + AddAssert("no ruleset selected", () => selector.SelectedTab == null); + AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value)); + } + + private class TestRulesetSelector : BeatmapRulesetSelector + { + public new TabItem SelectedTab => base.SelectedTab; + + public new TabFillFlowContainer TabContainer => base.TabContainer; + } + } +} From 7d5f5d2fd9272e207bc26860e76f613ce01e38ec Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:55:33 +0300 Subject: [PATCH 235/966] Add ruleset selector to the beatmap overlay header --- osu.Game/Overlays/BeatmapSet/Header.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 260a989628..0e3d29c25b 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -16,6 +17,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Overlays.Direct; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -39,6 +41,7 @@ namespace osu.Game.Overlays.BeatmapSet public bool DownloadButtonsVisible => downloadButtonsContainer.Any(); + public readonly BeatmapRulesetSelector RulesetSelector; public readonly BeatmapPicker Picker; private readonly FavouriteButton favouriteButton; @@ -69,12 +72,17 @@ namespace osu.Game.Overlays.BeatmapSet { RelativeSizeAxes = Axes.X, Height = tabs_height, - Children = new[] + Children = new Drawable[] { tabsBg = new Box { RelativeSizeAxes = Axes.Both, }, + RulesetSelector = new BeatmapRulesetSelector + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + } }, }, new Container @@ -214,6 +222,13 @@ namespace osu.Game.Overlays.BeatmapSet }; } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + dependencies.CacheAs>(RulesetSelector.Current); + return dependencies; + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -223,7 +238,7 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.BindValueChanged(setInfo => { - Picker.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; + Picker.BeatmapSet = RulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; cover.BeatmapSet = setInfo.NewValue; if (setInfo.NewValue == null) From 555c82e9c9077f8e363aebb12e73ff07127aa97f Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:56:42 +0300 Subject: [PATCH 236/966] Filter beatmap difficulties by current ruleset --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 28947b6f22..e7a3d15401 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -17,6 +17,7 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -27,10 +28,11 @@ namespace osu.Game.Overlays.BeatmapSet private const float tile_icon_padding = 7; private const float tile_spacing = 2; - private readonly DifficultiesContainer difficulties; private readonly OsuSpriteText version, starRating; private readonly Statistic plays, favourites; + public readonly DifficultiesContainer Difficulties; + public readonly Bindable Beatmap = new Bindable(); private BeatmapSetInfo beatmapSet; @@ -50,11 +52,11 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDisplay() { - difficulties.Clear(); + Difficulties.Clear(); if (BeatmapSet != null) { - difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty).Select(b => new DifficultySelectorButton(b) + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) { State = DifficultySelectorState.NotSelected, OnHovered = beatmap => @@ -68,7 +70,7 @@ namespace osu.Game.Overlays.BeatmapSet } starRating.FadeOut(100); - Beatmap.Value = BeatmapSet?.Beatmaps.FirstOrDefault(); + Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap; plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; @@ -89,7 +91,7 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Vertical, Children = new Drawable[] { - difficulties = new DifficultiesContainer + Difficulties = new DifficultiesContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -147,6 +149,9 @@ namespace osu.Game.Overlays.BeatmapSet }; } + [Resolved] + private IBindable ruleset { get; set; } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -158,6 +163,8 @@ namespace osu.Game.Overlays.BeatmapSet { base.LoadComplete(); + ruleset.ValueChanged += r => updateDisplay(); + // done here so everything can bind in intialization and get the first trigger Beatmap.TriggerChange(); } @@ -169,10 +176,10 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDifficultyButtons() { - difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected); + Difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected); } - private class DifficultiesContainer : FillFlowContainer + public class DifficultiesContainer : FillFlowContainer { public Action OnLostHover; @@ -183,7 +190,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private class DifficultySelectorButton : OsuClickableContainer, IStateful + public class DifficultySelectorButton : OsuClickableContainer, IStateful { private const float transition_duration = 100; private const float size = 52; @@ -320,7 +327,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private enum DifficultySelectorState + public enum DifficultySelectorState { Selected, NotSelected, From 4f40a044258b392f8c0d42a672d5d492ab11779e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 17:57:39 +0300 Subject: [PATCH 237/966] Add tests ensuring correct behaviour with ruleset selection --- .../Online/TestSceneBeatmapSetOverlay.cs | 70 +++++++++++++++---- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 9f03d947b9..6c7a3e4108 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; @@ -40,24 +41,19 @@ namespace osu.Game.Tests.Visual.Online typeof(PreviewButton), typeof(SuccessRate), typeof(BeatmapAvailability), + typeof(BeatmapRulesetSelector), + typeof(BeatmapRulesetTabItem), }; protected override bool UseOnlineAPI => true; - private RulesetInfo taikoRuleset; - private RulesetInfo maniaRuleset; - public TestSceneBeatmapSetOverlay() { Add(overlay = new TestBeatmapSetOverlay()); } - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - taikoRuleset = rulesets.GetRuleset(1); - maniaRuleset = rulesets.GetRuleset(3); - } + [Resolved] + private RulesetStore rulesets { get; set; } [Test] public void TestLoading() @@ -111,7 +107,7 @@ namespace osu.Game.Tests.Visual.Online StarDifficulty = 9.99, Version = @"TEST", Length = 456000, - Ruleset = maniaRuleset, + Ruleset = rulesets.GetRuleset(3), BaseDifficulty = new BeatmapDifficulty { CircleSize = 1, @@ -189,7 +185,7 @@ namespace osu.Game.Tests.Visual.Online StarDifficulty = 5.67, Version = @"ANOTHER TEST", Length = 123000, - Ruleset = taikoRuleset, + Ruleset = rulesets.GetRuleset(1), BaseDifficulty = new BeatmapDifficulty { CircleSize = 9, @@ -217,6 +213,54 @@ namespace osu.Game.Tests.Visual.Online downloadAssert(false); } + [Test] + public void TestMultipleRulesets() + { + AddStep("show multiple rulesets beatmap", () => + { + var beatmaps = new List(); + + foreach (var ruleset in rulesets.AvailableRulesets.Skip(1)) + { + beatmaps.Add(new BeatmapInfo + { + Version = ruleset.Name, + Ruleset = ruleset, + BaseDifficulty = new BeatmapDifficulty(), + OnlineInfo = new BeatmapOnlineInfo(), + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), + }, + }); + } + + overlay.ShowBeatmapSet(new BeatmapSetInfo + { + Metadata = new BeatmapMetadata + { + Title = @"multiple rulesets beatmap", + Artist = @"none", + Author = new User + { + Username = "BanchoBot", + Id = 3, + } + }, + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers(), + }, + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, + Beatmaps = beatmaps + }); + }); + + AddAssert("shown beatmaps of current ruleset", () => overlay.Header.Picker.Difficulties.All(b => b.Beatmap.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value))); + AddAssert("left-most beatmap selected", () => overlay.Header.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected); + } + [Test] public void TestHide() { @@ -281,12 +325,12 @@ namespace osu.Game.Tests.Visual.Online private void downloadAssert(bool shown) { - AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.DownloadButtonsVisible == shown); + AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.DownloadButtonsVisible == shown); } private class TestBeatmapSetOverlay : BeatmapSetOverlay { - public bool DownloadButtonsVisible => Header.DownloadButtonsVisible; + public new Header Header => base.Header; } } } From 76c74719a44f2aa461cebf93cd2b71e476663632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Oct 2019 17:00:51 +0200 Subject: [PATCH 238/966] Add test for fallback decoder overwrite LegacyDifficultyCalculatorBeatmapDecoder was registered as a fallback decoder in commit ffde389 for future use in the server-side difficulty calculation components. Due to the pre-existing fallback registrations this causes a runtime crash when the diffcalc components are started. Add a test reproducing this scenario to prevent the issue from resurfacing in the future. --- .../Formats/LegacyBeatmapDecoderTest.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index f6c0dbbecf..de516d3142 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -591,5 +591,27 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.Throws(() => Decoder.GetDecoder(stream)); } } + + [Test] + public void TestAllowFallbackDecoderOverwrite() + { + Decoder decoder = null; + + using (var resStream = TestResources.OpenResource("corrupted-header.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); + Assert.IsInstanceOf(decoder); + } + + Assert.DoesNotThrow(LegacyDifficultyCalculatorBeatmapDecoder.Register); + + using (var resStream = TestResources.OpenResource("corrupted-header.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + Assert.DoesNotThrow(() => decoder = Decoder.GetDecoder(stream)); + Assert.IsInstanceOf(decoder); + } + } } } From 0c4f24825969c64775705b8feb9297af2f4fc9ac Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 18:02:13 +0300 Subject: [PATCH 239/966] Fix CI issues --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 0847272e1f..1abe103fc8 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet beatmapSet = value; - foreach (BeatmapRulesetTabItem tab in TabContainer.TabItems) + foreach (var tab in TabContainer.TabItems.OfType()) tab.SetBeatmaps(beatmapSet?.Beatmaps.FindAll(b => b.Ruleset.Equals(tab.Value))); var firstRuleset = beatmapSet?.Beatmaps.OrderBy(b => b.Ruleset.ID).FirstOrDefault()?.Ruleset; From 7c2c537bc9cca82740ea9df51f65c3f8047de372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Oct 2019 17:23:33 +0200 Subject: [PATCH 240/966] Allow fallback decoder overwrite To fix the runtime crashes in difficulty calculation components, remove the check for pre-existing fallback registration along with the exception. The xmldoc for the registration function has been extended to make users aware of possible consequences of calling it. --- osu.Game/Beatmaps/Formats/Decoder.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index 045eb2d14d..40c329eb7e 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -93,14 +93,12 @@ namespace osu.Game.Beatmaps.Formats /// /// Registers a fallback decoder instantiation function. /// The fallback will be returned if the first non-empty line of the decoded stream does not match any known magic. + /// Calling this method will overwrite any existing global fallback registration for type - use with caution. /// /// Type of object being decoded. /// A function that constructs the fallback. protected static void SetFallbackDecoder(Func constructor) { - if (fallback_decoders.ContainsKey(typeof(T))) - throw new InvalidOperationException($"A fallback decoder was already added for type {typeof(T)}."); - fallback_decoders[typeof(T)] = constructor; } } From 6985249d90e63e8e18ca92dd31c056eed82f35af Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 4 Oct 2019 21:18:03 +0300 Subject: [PATCH 241/966] Simplify properties --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 1abe103fc8..bfb188a83b 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -36,15 +36,15 @@ namespace osu.Game.Overlays.BeatmapSet public BeatmapRulesetSelector() { AutoSizeAxes = Axes.Both; - TabContainer.Spacing = new Vector2(10, 0); } protected override TabItem CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value); protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer { - Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), }; } } From e7ba6ef5c43fcf1c55d93a86cb0773ea4d8070f2 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 4 Oct 2019 14:32:43 -0700 Subject: [PATCH 242/966] Fix keybinding order of beatmap options --- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 4df6e6a3f3..9368bac69f 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select { ValidForResume = false; Edit(); - }, Key.Number3); + }, Key.Number4); } public override void OnResuming(IScreen last) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 452c63a18c..ee2e40dcd9 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -230,9 +230,9 @@ namespace osu.Game.Screens.Select Footer.AddButton(new FooterButtonRandom { Action = triggerRandom }); Footer.AddButton(new FooterButtonOptions(), BeatmapOptions); - BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); - BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null, Key.Number1); - BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo), Key.Number2); + BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number1, float.MaxValue); + BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null, Key.Number2); + BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo), Key.Number3); } if (this.beatmaps == null) From 5d460eaf6b8a9c05d54c61f2cd01cfddb2636386 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 4 Oct 2019 17:14:19 -0700 Subject: [PATCH 243/966] Remove depth specification and button order regression --- osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs | 5 ++--- osu.Game/Screens/Select/SongSelect.cs | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index ede526f9da..b831ae274c 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -93,7 +93,7 @@ namespace osu.Game.Screens.Select.Options /// Lower depth to be put on the left, and higher to be put on the right. /// Notice this is different to ! /// - public void AddButton(string firstLine, string secondLine, IconUsage icon, Color4 colour, Action action, Key? hotkey = null, float depth = 0) + public void AddButton(string firstLine, string secondLine, IconUsage icon, Color4 colour, Action action, Key? hotkey = null) { var button = new BeatmapOptionsButton { @@ -101,7 +101,6 @@ namespace osu.Game.Screens.Select.Options SecondLineText = secondLine, Icon = icon, ButtonColour = colour, - Depth = depth, Action = () => { Hide(); @@ -110,7 +109,7 @@ namespace osu.Game.Screens.Select.Options HotKey = hotkey }; - buttonsContainer.Insert((int)depth, button); + buttonsContainer.Add(button); } } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ee2e40dcd9..59a143728c 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -230,9 +230,9 @@ namespace osu.Game.Screens.Select Footer.AddButton(new FooterButtonRandom { Action = triggerRandom }); Footer.AddButton(new FooterButtonOptions(), BeatmapOptions); - BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number1, float.MaxValue); - BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null, Key.Number2); - BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo), Key.Number3); + BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null, Key.Number1); + BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo), Key.Number2); + BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number3); } if (this.beatmaps == null) From de658c932e6ef23ce6511d15cabf28b836f94416 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 4 Oct 2019 17:22:42 -0700 Subject: [PATCH 244/966] Fix test regression --- .../Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs index ecdc484887..f55c099d83 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs @@ -18,8 +18,8 @@ namespace osu.Game.Tests.Visual.SongSelect overlay.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, Color4.Purple, null, Key.Number1); overlay.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, Color4.Purple, null, Key.Number2); - overlay.AddButton(@"Edit", @"Beatmap", FontAwesome.Solid.PencilAlt, Color4.Yellow, null, Key.Number3); - overlay.AddButton(@"Delete", @"Beatmap", FontAwesome.Solid.Trash, Color4.Pink, null, Key.Number4, float.MaxValue); + overlay.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, Color4.Pink, null, Key.Number3); + overlay.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, Color4.Yellow, null, Key.Number4); Add(overlay); From a71db11ea544cacf62fdd22da93a9f89a6523f5c Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 4 Oct 2019 18:38:44 -0700 Subject: [PATCH 245/966] Remove depth parameter description --- osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index b831ae274c..c01970f536 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -89,10 +89,6 @@ namespace osu.Game.Screens.Select.Options /// Icon of the button. /// Hotkey of the button. /// Binding the button does. - /// - /// Lower depth to be put on the left, and higher to be put on the right. - /// Notice this is different to ! - /// public void AddButton(string firstLine, string secondLine, IconUsage icon, Color4 colour, Action action, Key? hotkey = null) { var button = new BeatmapOptionsButton From ba1a8547011d721f61ef1798b6dab6ed6d0e083e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 5 Oct 2019 10:30:32 +0300 Subject: [PATCH 246/966] Use IEnumerable.Where<>() rather than List.FindAll() Saves a whole list allocation --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index e7a3d15401..bffe779da1 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.BeatmapSet if (BeatmapSet != null) { - Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Where(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b) { State = DifficultySelectorState.NotSelected, OnHovered = beatmap => From e257f4ca04481e6b43ef8ec52337c7c364218b56 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sat, 5 Oct 2019 10:31:44 -0700 Subject: [PATCH 247/966] Resume music to same position when exiting gameplay --- osu.Game/Screens/Select/SongSelect.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 59a143728c..d9ddfa2a94 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -413,7 +413,7 @@ namespace osu.Game.Screens.Select Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous); if (this.IsCurrentScreen() && Beatmap.Value?.Track != previous?.Track) - ensurePlayingSelected(); + ensurePlayingSelected(true); if (beatmap != null) { @@ -585,18 +585,14 @@ namespace osu.Game.Screens.Select { Track track = Beatmap.Value.Track; - if (!track.IsRunning || restart) + if (!track.IsRunning) { track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; - if (music != null) - { - // use the global music controller (when available) to cancel a potential local user paused state. - music.SeekTo(track.RestartPoint); - music.Play(); - } - else + if (restart) track.Restart(); + else + track.Start(); } } From bdea75b99584c2624cfc9acff6fc811f332ebc07 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sat, 5 Oct 2019 23:53:05 +0300 Subject: [PATCH 248/966] Autoscroll playlist on song change --- osu.Game/Configuration/OsuConfigManager.cs | 5 +++- osu.Game/Overlays/Music/PlaylistList.cs | 11 +++++++- .../Sections/Audio/PlaylistSettings.cs | 27 +++++++++++++++++++ .../Settings/Sections/AudioSection.cs | 1 + 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index c0ce08ba08..75cc961a9e 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -117,6 +117,8 @@ namespace osu.Game.Configuration Set(OsuSetting.UIHoldActivationDelay, 200f, 0f, 500f, 50f); Set(OsuSetting.IntroSequence, IntroSequence.Triangles); + + Set(OsuSetting.FollowPlayback, true); } public OsuConfigManager(Storage storage) @@ -186,6 +188,7 @@ namespace osu.Game.Configuration UIScale, IntroSequence, UIHoldActivationDelay, - HitLighting + HitLighting, + FollowPlayback } } diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 5b528c5ab2..95b4a28125 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osuTK; @@ -52,6 +53,8 @@ namespace osu.Game.Overlays.Music private IBindableList beatmaps; + private IBindable followPlayback; + [Resolved] private MusicController musicController { get; set; } @@ -76,8 +79,10 @@ namespace osu.Game.Overlays.Music } [BackgroundDependencyLoader] - private void load(IBindable beatmap) + private void load(IBindable beatmap, OsuConfigManager configManager) { + followPlayback = configManager.GetBindable(OsuSetting.FollowPlayback); + beatmaps = musicController.BeatmapSets.GetBoundCopy(); beatmaps.ItemsAdded += i => i.ForEach(addBeatmapSet); beatmaps.ItemsRemoved += i => i.ForEach(removeBeatmapSet); @@ -109,7 +114,11 @@ namespace osu.Game.Overlays.Music private void updateSelectedSet() { foreach (PlaylistItem s in items.Children) + { s.Selected = s.BeatmapSetInfo.ID == beatmapBacking.Value.BeatmapSetInfo?.ID; + if (s.Selected && followPlayback.Value) + ScrollIntoView(s); + } } public string SearchTerm diff --git a/osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs new file mode 100644 index 0000000000..5de99e24af --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs @@ -0,0 +1,27 @@ +// 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.Allocation; +using osu.Framework.Graphics; +using osu.Game.Configuration; + +namespace osu.Game.Overlays.Settings.Sections.Audio +{ + public class PlaylistSettings : SettingsSubsection + { + protected override string Header => "Playlist"; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + Children = new Drawable[] + { + new SettingsCheckbox + { + LabelText = "Follow playback", + Bindable = config.GetBindable(OsuSetting.FollowPlayback) + } + }; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/AudioSection.cs b/osu.Game/Overlays/Settings/Sections/AudioSection.cs index 772f5c2039..dd67493a75 100644 --- a/osu.Game/Overlays/Settings/Sections/AudioSection.cs +++ b/osu.Game/Overlays/Settings/Sections/AudioSection.cs @@ -20,6 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections new VolumeSettings(), new OffsetSettings(), new MainMenuSettings(), + new PlaylistSettings() }; } } From eda4a27b45e66c8231c7aeea7c9c2915bbfca74b Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sun, 6 Oct 2019 15:06:25 +0300 Subject: [PATCH 249/966] Move FollowPlayback setting to User Interface subsection --- .../Sections/Audio/PlaylistSettings.cs | 27 ------------------- .../Settings/Sections/AudioSection.cs | 3 +-- .../Graphics/UserInterfaceSettings.cs | 5 ++++ 3 files changed, 6 insertions(+), 29 deletions(-) delete mode 100644 osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs diff --git a/osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs deleted file mode 100644 index 5de99e24af..0000000000 --- a/osu.Game/Overlays/Settings/Sections/Audio/PlaylistSettings.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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.Allocation; -using osu.Framework.Graphics; -using osu.Game.Configuration; - -namespace osu.Game.Overlays.Settings.Sections.Audio -{ - public class PlaylistSettings : SettingsSubsection - { - protected override string Header => "Playlist"; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - Children = new Drawable[] - { - new SettingsCheckbox - { - LabelText = "Follow playback", - Bindable = config.GetBindable(OsuSetting.FollowPlayback) - } - }; - } - } -} diff --git a/osu.Game/Overlays/Settings/Sections/AudioSection.cs b/osu.Game/Overlays/Settings/Sections/AudioSection.cs index dd67493a75..7ca313a751 100644 --- a/osu.Game/Overlays/Settings/Sections/AudioSection.cs +++ b/osu.Game/Overlays/Settings/Sections/AudioSection.cs @@ -19,8 +19,7 @@ namespace osu.Game.Overlays.Settings.Sections new AudioDevicesSettings(), new VolumeSettings(), new OffsetSettings(), - new MainMenuSettings(), - new PlaylistSettings() + new MainMenuSettings() }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs index a8953ac3a2..2678d4c11a 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs @@ -17,6 +17,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { Children = new Drawable[] { + new SettingsCheckbox + { + LabelText = "Scroll playlist on song change", + Bindable = config.GetBindable(OsuSetting.FollowPlayback) + }, new SettingsCheckbox { LabelText = "Rotate cursor when dragging", From 38c1cee5fdbb913c771ddbf373ca3fea3d062235 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 6 Oct 2019 10:22:55 -0700 Subject: [PATCH 250/966] Fix tab controls overflowing --- .../Overlays/Chat/Tabs/ChannelTabControl.cs | 13 ++----------- osu.Game/Overlays/ChatOverlay.cs | 9 +++++++++ .../SearchableListFilterControl.cs | 10 +++++++++- .../Select/BeatmapDetailAreaTabControl.cs | 18 +++++++++++++++--- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 612379d339..8b88d81b88 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -9,7 +9,6 @@ using osuTK; using System; using System.Linq; using osu.Framework.Bindables; -using osu.Framework.Graphics.Sprites; namespace osu.Game.Overlays.Chat.Tabs { @@ -25,19 +24,11 @@ namespace osu.Game.Overlays.Chat.Tabs public ChannelTabControl() { - TabContainer.Margin = new MarginPadding { Left = 50 }; + Padding = new MarginPadding { Left = 50 }; + TabContainer.Spacing = new Vector2(-SHEAR_WIDTH, 0); TabContainer.Masking = false; - AddInternal(new SpriteIcon - { - Icon = FontAwesome.Solid.Comments, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(20), - Margin = new MarginPadding(10), - }); - AddTabItem(selectorTab = new ChannelSelectorTabItem()); ChannelSelectorActive.BindTo(selectorTab.Active); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 0cadbdfd31..33bcc4c139 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -21,6 +21,7 @@ using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; using osuTK.Input; +using osu.Framework.Graphics.Sprites; namespace osu.Game.Overlays { @@ -156,6 +157,14 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, + new SpriteIcon + { + Icon = FontAwesome.Solid.Comments, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(20), + Margin = new MarginPadding(10), + }, ChannelTabControl = CreateChannelTabControl().With(d => { d.Anchor = Anchor.BottomLeft; diff --git a/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs b/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs index a0c4e9a080..d72e99289e 100644 --- a/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs +++ b/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs @@ -18,6 +18,7 @@ namespace osu.Game.Overlays.SearchableList private const float padding = 10; private readonly Container filterContainer; + private readonly Container tabsContainer; private readonly Box tabStrip; public readonly SearchTextBox Search; @@ -85,9 +86,14 @@ namespace osu.Game.Overlays.SearchableList AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Top = controls != null ? padding : 0 }, }, - Tabs = new PageTabControl + tabsContainer = new Container { RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = Tabs = new PageTabControl + { + RelativeSizeAxes = Axes.X, + }, }, new Box //keep the tab strip part of autosize, but don't put it in the flow container { @@ -127,6 +133,8 @@ namespace osu.Game.Overlays.SearchableList Height = filterContainer.Height; DisplayStyleControl.Margin = new MarginPadding { Top = filterContainer.Height - 35, Right = SearchableListOverlay.WIDTH_PADDING }; + + tabsContainer.Padding = new MarginPadding { Right = DisplayStyleControl.Width }; } private class FilterSearchTextBox : SearchTextBox diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index 6caef8e2aa..4ca629fee9 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -20,6 +20,7 @@ namespace osu.Game.Screens.Select public static readonly float HEIGHT = 24; private readonly OsuTabControlCheckbox modsCheckbox; private readonly OsuTabControl tabs; + private readonly Container tabsContainer; public Action OnFilter; //passed the selected tab and if mods is checked @@ -39,11 +40,15 @@ namespace osu.Game.Screens.Select Height = 1, Colour = Color4.White.Opacity(0.2f), }, - tabs = new OsuTabControl + tabsContainer = new Container { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, + Child = tabs = new OsuTabControl + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + }, }, modsCheckbox = new OsuTabControlCheckbox { @@ -69,6 +74,13 @@ namespace osu.Game.Screens.Select tabs.Current.TriggerChange(); } + protected override void Update() + { + base.Update(); + + tabsContainer.Padding = new MarginPadding { Right = modsCheckbox.Width }; + } + private void invokeOnFilter() { OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value); From 11d937beab1708fb1354994b017e08e98cb5cc78 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 6 Oct 2019 10:24:33 -0700 Subject: [PATCH 251/966] Fix beatmap detail area tab dropdown being blocked by content --- osu.Game/Screens/Select/BeatmapDetailArea.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 5348de68d6..71733c9f06 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -36,6 +36,11 @@ namespace osu.Game.Screens.Select { AddRangeInternal(new Drawable[] { + content = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = BeatmapDetailAreaTabControl.HEIGHT }, + }, new BeatmapDetailAreaTabControl { RelativeSizeAxes = Axes.X, @@ -58,11 +63,6 @@ namespace osu.Game.Screens.Select } }, }, - content = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = BeatmapDetailAreaTabControl.HEIGHT }, - }, }); AddRange(new Drawable[] From 62c4c1266ef8c1dc71324021bd4808abbb7b6205 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Oct 2019 14:45:26 +0900 Subject: [PATCH 252/966] Move private functions to bottom --- .../SongSelect/TestSceneBeatmapCarousel.cs | 202 +++++++++--------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 6bdd94db21..527367fdb8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -58,107 +58,6 @@ namespace osu.Game.Tests.Visual.SongSelect }); } - private void loadBeatmaps(List beatmapSets = null) - { - if (beatmapSets == null) - { - beatmapSets = new List(); - - for (int i = 1; i <= set_count; i++) - beatmapSets.Add(createTestBeatmapSet(i)); - } - - bool changed = false; - AddStep($"Load {beatmapSets.Count} Beatmaps", () => - { - carousel.Filter(new FilterCriteria()); - carousel.BeatmapSetsChanged = () => changed = true; - carousel.BeatmapSets = beatmapSets; - }); - - AddUntilStep("Wait for load", () => changed); - } - - private void ensureRandomFetchSuccess() => - AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet); - - private void waitForSelection(int set, int? diff = null) => - AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () => - { - if (diff != null) - return carousel.SelectedBeatmap == carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff.Value - 1).First(); - - return carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Contains(carousel.SelectedBeatmap); - }); - - private void setSelected(int set, int diff) => - AddStep($"select set{set} diff{diff}", () => - carousel.SelectBeatmap(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First())); - - private void advanceSelection(bool diff, int direction = 1, int count = 1) - { - if (count == 1) - AddStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => - carousel.SelectNext(direction, !diff)); - else - { - AddRepeatStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => - carousel.SelectNext(direction, !diff), count); - } - } - - private void checkVisibleItemCount(bool diff, int count) => - AddAssert($"{count} {(diff ? "diffs" : "sets")} visible", () => - carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count); - - private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null); - - private void nextRandom() => - AddStep("select random next", () => - { - carousel.RandomAlgorithm.Value = RandomSelectAlgorithm.RandomPermutation; - - if (!selectedSets.Any() && carousel.SelectedBeatmap != null) - selectedSets.Push(carousel.SelectedBeatmapSet); - - carousel.SelectNextRandom(); - selectedSets.Push(carousel.SelectedBeatmapSet); - }); - - private void ensureRandomDidntRepeat() => - AddAssert("ensure no repeats", () => selectedSets.Distinct().Count() == selectedSets.Count); - - private void prevRandom() => AddStep("select random last", () => - { - carousel.SelectPreviousRandom(); - selectedSets.Pop(); - }); - - private bool selectedBeatmapVisible() - { - var currentlySelected = carousel.Items.Find(s => s.Item is CarouselBeatmap && s.Item.State.Value == CarouselItemState.Selected); - if (currentlySelected == null) - return true; - - return currentlySelected.Item.Visible; - } - - private void checkInvisibleDifficultiesUnselectable() - { - nextRandom(); - AddAssert("Selection is visible", selectedBeatmapVisible); - } - - private void checkNonmatchingFilter() - { - AddStep("Toggle non-matching filter", () => - { - carousel.Filter(new FilterCriteria { SearchText = "Dingo" }, false); - carousel.Filter(new FilterCriteria(), false); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID); - }); - } - /// /// Test keyboard traversal /// @@ -482,6 +381,107 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selection was random", () => eagerSelectedIDs.Count > 1); } + private void loadBeatmaps(List beatmapSets = null) + { + if (beatmapSets == null) + { + beatmapSets = new List(); + + for (int i = 1; i <= set_count; i++) + beatmapSets.Add(createTestBeatmapSet(i)); + } + + bool changed = false; + AddStep($"Load {beatmapSets.Count} Beatmaps", () => + { + carousel.Filter(new FilterCriteria()); + carousel.BeatmapSetsChanged = () => changed = true; + carousel.BeatmapSets = beatmapSets; + }); + + AddUntilStep("Wait for load", () => changed); + } + + private void ensureRandomFetchSuccess() => + AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet); + + private void waitForSelection(int set, int? diff = null) => + AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () => + { + if (diff != null) + return carousel.SelectedBeatmap == carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff.Value - 1).First(); + + return carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Contains(carousel.SelectedBeatmap); + }); + + private void setSelected(int set, int diff) => + AddStep($"select set{set} diff{diff}", () => + carousel.SelectBeatmap(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First())); + + private void advanceSelection(bool diff, int direction = 1, int count = 1) + { + if (count == 1) + AddStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => + carousel.SelectNext(direction, !diff)); + else + { + AddRepeatStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => + carousel.SelectNext(direction, !diff), count); + } + } + + private void checkVisibleItemCount(bool diff, int count) => + AddAssert($"{count} {(diff ? "diffs" : "sets")} visible", () => + carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count); + + private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null); + + private void nextRandom() => + AddStep("select random next", () => + { + carousel.RandomAlgorithm.Value = RandomSelectAlgorithm.RandomPermutation; + + if (!selectedSets.Any() && carousel.SelectedBeatmap != null) + selectedSets.Push(carousel.SelectedBeatmapSet); + + carousel.SelectNextRandom(); + selectedSets.Push(carousel.SelectedBeatmapSet); + }); + + private void ensureRandomDidntRepeat() => + AddAssert("ensure no repeats", () => selectedSets.Distinct().Count() == selectedSets.Count); + + private void prevRandom() => AddStep("select random last", () => + { + carousel.SelectPreviousRandom(); + selectedSets.Pop(); + }); + + private bool selectedBeatmapVisible() + { + var currentlySelected = carousel.Items.Find(s => s.Item is CarouselBeatmap && s.Item.State.Value == CarouselItemState.Selected); + if (currentlySelected == null) + return true; + + return currentlySelected.Item.Visible; + } + + private void checkInvisibleDifficultiesUnselectable() + { + nextRandom(); + AddAssert("Selection is visible", selectedBeatmapVisible); + } + + private void checkNonmatchingFilter() + { + AddStep("Toggle non-matching filter", () => + { + carousel.Filter(new FilterCriteria { SearchText = "Dingo" }, false); + carousel.Filter(new FilterCriteria(), false); + eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID); + }); + } + private BeatmapSetInfo createTestBeatmapSet(int id) { return new BeatmapSetInfo From 46d6c5ec3b6832d353f033d9284d761f423943db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Oct 2019 15:13:58 +0900 Subject: [PATCH 253/966] Add failing test --- .../SongSelect/TestSceneBeatmapCarousel.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 527367fdb8..f87d6ebebb 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -245,6 +245,30 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert($"Check #{set_count} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Title.EndsWith($"#{set_count}!")); } + [Test] + public void TestSortingWithFiltered() + { + List sets = new List(); + + for (int i = 0; i < 3; i++) + { + var set = createTestBeatmapSet(i); + set.Beatmaps[0].StarDifficulty = 3 - i; + set.Beatmaps[2].StarDifficulty = 6 + i; + sets.Add(set); + } + + loadBeatmaps(sets); + + AddStep("Filter to normal", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Normal" }, false)); + AddAssert("Check first set at end", () => carousel.BeatmapSets.First() == sets.Last()); + AddAssert("Check last set at start", () => carousel.BeatmapSets.Last() == sets.First()); + + AddStep("Filter to insane", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Insane" }, false)); + AddAssert("Check first set at start", () => carousel.BeatmapSets.First() == sets.First()); + AddAssert("Check last set at end", () => carousel.BeatmapSets.Last() == sets.Last()); + } + [Test] public void TestRemoveAll() { From f15953d65ce00c38a2544234c426c33f55429cb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Oct 2019 15:16:26 +0900 Subject: [PATCH 254/966] Fix carousel including filtered difficulties in sort comparisons --- .../Select/Carousel/CarouselBeatmapSet.cs | 23 ++++++++++++++++--- .../Screens/Select/Carousel/CarouselGroup.cs | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 5a3996bb49..35816fe620 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -49,16 +49,33 @@ namespace osu.Game.Screens.Select.Carousel return otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); case SortMode.BPM: - return BeatmapSet.MaxBPM.CompareTo(otherSet.BeatmapSet.MaxBPM); + return compareUsingAggregateMax(otherSet, b => b.BPM); case SortMode.Length: - return BeatmapSet.MaxLength.CompareTo(otherSet.BeatmapSet.MaxLength); + return compareUsingAggregateMax(otherSet, b => b.Length); case SortMode.Difficulty: - return BeatmapSet.MaxStarDifficulty.CompareTo(otherSet.BeatmapSet.MaxStarDifficulty); + return compareUsingAggregateMax(otherSet, b => b.StarDifficulty); } } + /// + /// All beatmaps which are not filtered and valid for display. + /// + protected IEnumerable ValidBeatmaps => Beatmaps.Where(b => !b.Filtered.Value).Select(b => b.Beatmap); + + private int compareUsingAggregateMax(CarouselBeatmapSet other, Func func) + { + var ourBeatmaps = ValidBeatmaps.Any(); + var otherBeatmaps = other.ValidBeatmaps.Any(); + + if (!ourBeatmaps && !otherBeatmaps) return 0; + if (!ourBeatmaps) return -1; + if (!otherBeatmaps) return 1; + + return ValidBeatmaps.Max(func).CompareTo(other.ValidBeatmaps.Max(func)); + } + public override void Filter(FilterCriteria criteria) { base.Filter(criteria); diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs index 6ebd2d41cc..09b728abeb 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs @@ -83,8 +83,8 @@ namespace osu.Game.Screens.Select.Carousel var children = new List(InternalChildren); - children.Sort((x, y) => x.CompareTo(criteria, y)); children.ForEach(c => c.Filter(criteria)); + children.Sort((x, y) => x.CompareTo(criteria, y)); InternalChildren = children; } From e265beb289a3d1df5c5d0645526884e85c410ac9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 7 Oct 2019 18:49:59 +0900 Subject: [PATCH 255/966] Fix merge error --- .../Blueprints/HitCircles/HitCirclePlacementBlueprint.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index 38584ce898..6c08990ad6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -21,6 +21,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles InternalChild = circlePiece = new HitCirclePiece(); } + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(HitObject); + } + protected override bool OnClick(ClickEvent e) { HitObject.StartTime = EditorClock.CurrentTime; From 2d707b2b65bb4baa189e4cb68c3e9d3bbbfeff54 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 15:36:23 +0300 Subject: [PATCH 256/966] Implement PostBeatmapFavouriteRequest --- .../Requests/PostBeatmapFavouriteRequest.cs | 36 +++++++++++++++++++ .../BeatmapSet/Buttons/FavouriteButton.cs | 24 ++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs diff --git a/osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs b/osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs new file mode 100644 index 0000000000..f3724230cb --- /dev/null +++ b/osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs @@ -0,0 +1,36 @@ +// 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.IO.Network; +using System.Net.Http; + +namespace osu.Game.Online.API.Requests +{ + public class PostBeatmapFavouriteRequest : APIRequest + { + private readonly int id; + private readonly BeatmapFavouriteAction action; + + public PostBeatmapFavouriteRequest(int id, BeatmapFavouriteAction action) + { + this.id = id; + this.action = action; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + req.AddParameter(@"action", action.ToString().ToLowerInvariant()); + return req; + } + + protected override string Target => $@"beatmapsets/{id}/favourites"; + } + + public enum BeatmapFavouriteAction + { + Favourite, + UnFavourite + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index 11f56bc163..23325b8765 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -10,6 +10,9 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osuTK; namespace osu.Game.Overlays.BeatmapSet.Buttons @@ -20,8 +23,11 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private readonly Bindable favourited = new Bindable(); + private PostBeatmapFavouriteRequest request; + private DimmedLoadingLayer loading; + [BackgroundDependencyLoader] - private void load() + private void load(IAPIProvider api) { Container pink; SpriteIcon icon; @@ -55,6 +61,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons Size = new Vector2(18), Shadow = false, }, + loading = new DimmedLoadingLayer(), }); BeatmapSet.BindValueChanged(setInfo => @@ -67,6 +74,8 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons favourited.ValueChanged += favourited => { + loading.Hide(); + if (favourited.NewValue) { pink.FadeIn(200); @@ -78,6 +87,19 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons icon.Icon = FontAwesome.Regular.Heart; } }; + + Action = () => + { + if (loading.State.Value == Visibility.Visible) + return; + + loading.Show(); + + request?.Cancel(); + request = new PostBeatmapFavouriteRequest(BeatmapSet.Value?.OnlineBeatmapSetID ?? 0, favourited.Value ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite); + request.Success += () => favourited.Value = !favourited.Value; + api.Queue(request); + }; } protected override void UpdateAfterChildren() From a7dc9bb582682c0b87ea047f1da9aa6b40a45ea0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 15:41:05 +0300 Subject: [PATCH 257/966] Add tooltip and remove pink layer --- .../BeatmapSet/Buttons/FavouriteButton.cs | 40 +++---------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index 23325b8765..fcea20ef11 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -5,11 +5,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -17,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class FavouriteButton : HeaderButton + public class FavouriteButton : HeaderButton, IHasTooltip { public readonly Bindable BeatmapSet = new Bindable(); @@ -26,33 +24,14 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private PostBeatmapFavouriteRequest request; private DimmedLoadingLayer loading; + public string TooltipText => (favourited.Value ? "Unfavourite" : "Favourite") + " this beatmapset"; + [BackgroundDependencyLoader] private void load(IAPIProvider api) { - Container pink; SpriteIcon icon; AddRange(new Drawable[] { - pink = new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = 0f, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"9f015f"), - }, - new Triangles - { - RelativeSizeAxes = Axes.Both, - ColourLight = OsuColour.FromHex(@"cb2187"), - ColourDark = OsuColour.FromHex(@"9f015f"), - TriangleScale = 1.5f, - }, - }, - }, icon = new SpriteIcon { Anchor = Anchor.Centre, @@ -76,16 +55,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { loading.Hide(); - if (favourited.NewValue) - { - pink.FadeIn(200); - icon.Icon = FontAwesome.Solid.Heart; - } - else - { - pink.FadeOut(200); - icon.Icon = FontAwesome.Regular.Heart; - } + icon.Icon = favourited.NewValue ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart; }; Action = () => From 76db200bd3efd8f3f1a93820e852cbdb9e54fdc8 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 16:48:05 +0300 Subject: [PATCH 258/966] Implement GetCommentsRequest --- .../Online/API/Requests/GetCommentsRequest.cs | 53 ++++++++++++++++++ .../API/Requests/Responses/APIComments.cs | 36 ++++++++++++ .../Online/API/Requests/Responses/Comment.cs | 56 +++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 osu.Game/Online/API/Requests/GetCommentsRequest.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APIComments.cs create mode 100644 osu.Game/Online/API/Requests/Responses/Comment.cs diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs new file mode 100644 index 0000000000..279a1905da --- /dev/null +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -0,0 +1,53 @@ +// 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.IO.Network; +using Humanizer; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetCommentsRequest : APIRequest + { + private readonly long id; + private readonly int page; + private readonly CommentableType type; + private readonly SortCommentsBy sort; + + public GetCommentsRequest(CommentableType type, long id, SortCommentsBy sort = SortCommentsBy.New, int page = 1) + { + this.type = type; + this.sort = sort; + this.id = id; + this.page = page; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + + req.AddParameter("commentable_type", type.ToString().Underscore().ToLowerInvariant()); + req.AddParameter("commentable_id", id.ToString()); + req.AddParameter("sort", sort.ToString()); + req.AddParameter("page", page.ToString()); + + return req; + } + + protected override string Target => "comments"; + } + + public enum CommentableType + { + Build, + Beatmapset, + NewsPost + } + + public enum SortCommentsBy + { + New, + Old, + Top + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs new file mode 100644 index 0000000000..158430a5b6 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -0,0 +1,36 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; +using osu.Game.Users; +using System.Collections.Generic; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIComments + { + [JsonProperty(@"comments")] + public List Comments { get; set; } + + [JsonProperty(@"has_more")] + public bool HasMore { get; set; } + + [JsonProperty(@"has_more_id")] + public long HasMoreId { get; set; } + + [JsonProperty(@"user_follow")] + public bool UserFollow { get; set; } + + [JsonProperty(@"included_comments")] + public List IncludedComments { get; set; } + + [JsonProperty(@"users")] + public List Users { get; set; } + + [JsonProperty(@"total")] + public int Total { get; set; } + + [JsonProperty(@"top_level_count")] + public int TopLevelCount { get; set; } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs new file mode 100644 index 0000000000..e157a10f8a --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; +using System; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class Comment + { + [JsonProperty(@"id")] + public long Id { get; set; } + + [JsonProperty(@"parent_id")] + public long ParentId { get; set; } + + [JsonProperty(@"user_id")] + public long UserId { get; set; } + + [JsonProperty(@"message")] + public string Message { get; set; } + + [JsonProperty(@"message_html")] + public string MessageHTML { get; set; } + + [JsonProperty(@"replies_count")] + public int RepliesCount { get; set; } + + [JsonProperty(@"votes_count")] + public int VotesCount { get; set; } + + [JsonProperty(@"commenatble_type")] + public string CommentableType { get; set; } + + [JsonProperty(@"commentable_id")] + public int CommentableId { get; set; } + + [JsonProperty(@"legacy_name")] + public string LegacyName { get; set; } + + [JsonProperty(@"created_at")] + public DateTimeOffset CreatedAt { get; set; } + + [JsonProperty(@"updated_at")] + public DateTimeOffset UpdatedAt { get; set; } + + [JsonProperty(@"deleted_at")] + public DateTimeOffset DeletedAt { get; set; } + + [JsonProperty(@"edited_at")] + public DateTimeOffset EditedAt { get; set; } + + [JsonProperty(@"edited_by_id")] + public long EditedById { get; set; } + } +} From 738580ec617a23789236575f2525606a6a4d227e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 16:58:24 +0300 Subject: [PATCH 259/966] Add IsTopLevel property --- osu.Game/Online/API/Requests/Responses/Comment.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e157a10f8a..6edf13d2da 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -11,8 +11,18 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"id")] public long Id { get; set; } + private long? parentId; + [JsonProperty(@"parent_id")] - public long ParentId { get; set; } + public long? ParentId + { + get => parentId; + set + { + parentId = value; + IsTopLevel = value != null; + } + } [JsonProperty(@"user_id")] public long UserId { get; set; } @@ -52,5 +62,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"edited_by_id")] public long EditedById { get; set; } + + public bool IsTopLevel { get; set; } } } From e772822bd5ee46afddc5bc14398e73f84ff84564 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 17:49:20 +0300 Subject: [PATCH 260/966] Basic implementation --- .../Online/TestSceneCommentsContainer.cs | 29 +++++ osu.Game/Overlays/CommentsContainer.cs | 110 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs create mode 100644 osu.Game/Overlays/CommentsContainer.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs new file mode 100644 index 0000000000..c99062d59b --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -0,0 +1,29 @@ +// 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.Collections.Generic; +using NUnit.Framework; +using osu.Game.Overlays; +using osu.Game.Online.API.Requests; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneCommentsContainer : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(CommentsContainer), + }; + + public TestSceneCommentsContainer() + { + AddStep("Big Black comments", () => + { + Clear(); + Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); + }); + } + } +} diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs new file mode 100644 index 0000000000..8ed6fd0878 --- /dev/null +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -0,0 +1,110 @@ +// 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.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Framework.Graphics; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Overlays +{ + public class CommentsContainer : CompositeDrawable + { + private readonly CommentableType type; + private readonly long id; + + public readonly Bindable Sort = new Bindable(); + + [Resolved] + private IAPIProvider api { get; set; } + + private readonly CommentsHeader header; + private readonly Box background; + + public CommentsContainer(CommentableType type, long id) + { + this.type = type; + this.id = id; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + header = new CommentsHeader + { + Sort = { BindTarget = Sort } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray3; + } + + private class CommentsHeader : CompositeDrawable + { + private const int height = 40; + private const int spacing = 10; + private const int padding = 50; + + public readonly Bindable Sort = new Bindable(); + + private readonly Box background; + + public CommentsHeader() + { + RelativeSizeAxes = Axes.X; + Height = height; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = padding }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new SpriteText + { + Font = OsuFont.GetFont(size: 14), + Text = @"Sort by" + } + } + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray4; + } + } + } +} From aa8df0fa20426b0beec6997a2f2a07895cdddbaf Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 18:26:07 +0300 Subject: [PATCH 261/966] Hook up api and implement some visual comments representation --- .../Online/TestSceneCommentsContainer.cs | 15 +++- .../API/Requests/Responses/APIComments.cs | 2 +- .../Online/API/Requests/Responses/Comment.cs | 8 +- osu.Game/Overlays/CommentsContainer.cs | 84 ++++++++++++++++++- 4 files changed, 99 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index c99062d59b..bf4117189a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Game.Overlays; using osu.Game.Online.API.Requests; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; namespace osu.Game.Tests.Visual.Online { @@ -17,12 +19,21 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsContainer), }; + protected override bool UseOnlineAPI => true; + public TestSceneCommentsContainer() { + BasicScrollContainer scrollFlow; + + Add(scrollFlow = new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + }); + AddStep("Big Black comments", () => { - Clear(); - Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); + scrollFlow.Clear(); + scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); }); } } diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index 158430a5b6..af7650e512 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online.API.Requests.Responses public bool HasMore { get; set; } [JsonProperty(@"has_more_id")] - public long HasMoreId { get; set; } + public long? HasMoreId { get; set; } [JsonProperty(@"user_follow")] public bool UserFollow { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 6edf13d2da..df5c812fa0 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -52,16 +52,16 @@ namespace osu.Game.Online.API.Requests.Responses public DateTimeOffset CreatedAt { get; set; } [JsonProperty(@"updated_at")] - public DateTimeOffset UpdatedAt { get; set; } + public DateTimeOffset? UpdatedAt { get; set; } [JsonProperty(@"deleted_at")] - public DateTimeOffset DeletedAt { get; set; } + public DateTimeOffset? DeletedAt { get; set; } [JsonProperty(@"edited_at")] - public DateTimeOffset EditedAt { get; set; } + public DateTimeOffset? EditedAt { get; set; } [JsonProperty(@"edited_by_id")] - public long EditedById { get; set; } + public long? EditedById { get; set; } public bool IsTopLevel { get; set; } } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index 8ed6fd0878..fce9b3f03b 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays { @@ -24,8 +25,14 @@ namespace osu.Game.Overlays [Resolved] private IAPIProvider api { get; set; } + [Resolved] + private OsuColour colours { get; set; } + + private GetCommentsRequest request; + private readonly CommentsHeader header; private readonly Box background; + private readonly FillFlowContainer content; public CommentsContainer(CommentableType type, long id) { @@ -40,15 +47,86 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, }, - header = new CommentsHeader + new FillFlowContainer { - Sort = { BindTarget = Sort } + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + header = new CommentsHeader + { + Sort = { BindTarget = Sort } + }, + content = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + } + } + } + }); + } + + protected override void LoadComplete() + { + Sort.BindValueChanged(onSortChanged, true); + base.LoadComplete(); + } + + private void onSortChanged(ValueChangedEvent sort) => getComments(); + + private void getComments() + { + request?.Cancel(); + request = new GetCommentsRequest(type, id, Sort.Value); + request.Success += onSuccess; + api.Queue(request); + } + + private void onSuccess(APIComments response) + { + content.Clear(); + + foreach (var c in response.Comments) + { + createDrawableComment(c); + } + } + + private void createDrawableComment(Comment comment) + { + content.Add(new Container + { + RelativeSizeAxes = Axes.X, + Height = 70, + Children = new Drawable[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = comment.MessageHTML, + }, + new Container + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = 1, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray1, + } + } } }); } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { background.Colour = colours.Gray3; } From cc6bf2f173b4d53c9fb568963c4685e133417254 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 18:45:22 +0300 Subject: [PATCH 262/966] Add IsDeleted property --- .../Online/API/Requests/Responses/Comment.cs | 16 ++++++++++++++-- osu.Game/Overlays/CommentsContainer.cs | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index df5c812fa0..e4b66ddeee 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -20,7 +20,7 @@ namespace osu.Game.Online.API.Requests.Responses set { parentId = value; - IsTopLevel = value != null; + IsTopLevel = value == null; } } @@ -54,8 +54,18 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"updated_at")] public DateTimeOffset? UpdatedAt { get; set; } + private DateTimeOffset? deletedAt; + [JsonProperty(@"deleted_at")] - public DateTimeOffset? DeletedAt { get; set; } + public DateTimeOffset? DeletedAt + { + get => deletedAt; + set + { + deletedAt = value; + IsDeleted = value != null; + } + } [JsonProperty(@"edited_at")] public DateTimeOffset? EditedAt { get; set; } @@ -64,5 +74,7 @@ namespace osu.Game.Online.API.Requests.Responses public long? EditedById { get; set; } public bool IsTopLevel { get; set; } + + public bool IsDeleted { get; set; } } } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index fce9b3f03b..b22fefb3de 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -30,7 +30,6 @@ namespace osu.Game.Overlays private GetCommentsRequest request; - private readonly CommentsHeader header; private readonly Box background; private readonly FillFlowContainer content; @@ -54,7 +53,7 @@ namespace osu.Game.Overlays Direction = FillDirection.Vertical, Children = new Drawable[] { - header = new CommentsHeader + new CommentsHeader { Sort = { BindTarget = Sort } }, @@ -91,7 +90,8 @@ namespace osu.Game.Overlays foreach (var c in response.Comments) { - createDrawableComment(c); + if (!c.IsDeleted) + createDrawableComment(c); } } From e00992dfd8f18cc9e99724099e75eae42d0a1424 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Mon, 7 Oct 2019 19:44:22 +0300 Subject: [PATCH 263/966] Remove FollowPlayback setting --- osu.Game/Configuration/OsuConfigManager.cs | 5 +---- osu.Game/Overlays/Music/PlaylistList.cs | 9 ++------- .../Settings/Sections/Graphics/UserInterfaceSettings.cs | 5 ----- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 75cc961a9e..c0ce08ba08 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -117,8 +117,6 @@ namespace osu.Game.Configuration Set(OsuSetting.UIHoldActivationDelay, 200f, 0f, 500f, 50f); Set(OsuSetting.IntroSequence, IntroSequence.Triangles); - - Set(OsuSetting.FollowPlayback, true); } public OsuConfigManager(Storage storage) @@ -188,7 +186,6 @@ namespace osu.Game.Configuration UIScale, IntroSequence, UIHoldActivationDelay, - HitLighting, - FollowPlayback + HitLighting } } diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 95b4a28125..f497bd5b8d 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osuTK; @@ -53,8 +52,6 @@ namespace osu.Game.Overlays.Music private IBindableList beatmaps; - private IBindable followPlayback; - [Resolved] private MusicController musicController { get; set; } @@ -79,10 +76,8 @@ namespace osu.Game.Overlays.Music } [BackgroundDependencyLoader] - private void load(IBindable beatmap, OsuConfigManager configManager) + private void load(IBindable beatmap) { - followPlayback = configManager.GetBindable(OsuSetting.FollowPlayback); - beatmaps = musicController.BeatmapSets.GetBoundCopy(); beatmaps.ItemsAdded += i => i.ForEach(addBeatmapSet); beatmaps.ItemsRemoved += i => i.ForEach(removeBeatmapSet); @@ -116,7 +111,7 @@ namespace osu.Game.Overlays.Music foreach (PlaylistItem s in items.Children) { s.Selected = s.BeatmapSetInfo.ID == beatmapBacking.Value.BeatmapSetInfo?.ID; - if (s.Selected && followPlayback.Value) + if (s.Selected) ScrollIntoView(s); } } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs index 2678d4c11a..a8953ac3a2 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs @@ -17,11 +17,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { Children = new Drawable[] { - new SettingsCheckbox - { - LabelText = "Scroll playlist on song change", - Bindable = config.GetBindable(OsuSetting.FollowPlayback) - }, new SettingsCheckbox { LabelText = "Rotate cursor when dragging", From 8e6e90eaecf467b2764f3b2497acac12d4977c30 Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 7 Oct 2019 16:11:40 -0700 Subject: [PATCH 264/966] Use fixed numbers for padding instead --- .../SearchableList/SearchableListFilterControl.cs | 6 ++---- .../Screens/Select/BeatmapDetailAreaTabControl.cs | 11 ++--------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs b/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs index d72e99289e..372da94b37 100644 --- a/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs +++ b/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs @@ -18,7 +18,6 @@ namespace osu.Game.Overlays.SearchableList private const float padding = 10; private readonly Container filterContainer; - private readonly Container tabsContainer; private readonly Box tabStrip; public readonly SearchTextBox Search; @@ -86,10 +85,11 @@ namespace osu.Game.Overlays.SearchableList AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Top = controls != null ? padding : 0 }, }, - tabsContainer = new Container + new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Right = 225 }, Child = Tabs = new PageTabControl { RelativeSizeAxes = Axes.X, @@ -133,8 +133,6 @@ namespace osu.Game.Overlays.SearchableList Height = filterContainer.Height; DisplayStyleControl.Margin = new MarginPadding { Top = filterContainer.Height - 35, Right = SearchableListOverlay.WIDTH_PADDING }; - - tabsContainer.Padding = new MarginPadding { Right = DisplayStyleControl.Width }; } private class FilterSearchTextBox : SearchTextBox diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index 4ca629fee9..38b1c6411b 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -20,7 +20,6 @@ namespace osu.Game.Screens.Select public static readonly float HEIGHT = 24; private readonly OsuTabControlCheckbox modsCheckbox; private readonly OsuTabControl tabs; - private readonly Container tabsContainer; public Action OnFilter; //passed the selected tab and if mods is checked @@ -40,9 +39,10 @@ namespace osu.Game.Screens.Select Height = 1, Colour = Color4.White.Opacity(0.2f), }, - tabsContainer = new Container + new Container { RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 100 }, Child = tabs = new OsuTabControl { Anchor = Anchor.BottomLeft, @@ -74,13 +74,6 @@ namespace osu.Game.Screens.Select tabs.Current.TriggerChange(); } - protected override void Update() - { - base.Update(); - - tabsContainer.Padding = new MarginPadding { Right = modsCheckbox.Width }; - } - private void invokeOnFilter() { OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value); From 9fdbe583262411aa5f863aec924459420e373c26 Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 7 Oct 2019 16:17:58 -0700 Subject: [PATCH 265/966] Fix dropdown header padding when selected mod filter is hidden --- osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index 38b1c6411b..bba72c7ee1 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -20,6 +20,7 @@ namespace osu.Game.Screens.Select public static readonly float HEIGHT = 24; private readonly OsuTabControlCheckbox modsCheckbox; private readonly OsuTabControl tabs; + private readonly Container tabsContainer; public Action OnFilter; //passed the selected tab and if mods is checked @@ -39,10 +40,9 @@ namespace osu.Game.Screens.Select Height = 1, Colour = Color4.White.Opacity(0.2f), }, - new Container + tabsContainer = new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 100 }, Child = tabs = new OsuTabControl { Anchor = Anchor.BottomLeft, @@ -79,6 +79,8 @@ namespace osu.Game.Screens.Select OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value); modsCheckbox.FadeTo(tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 1, 200, Easing.OutQuint); + + tabsContainer.Padding = new MarginPadding { Right = tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 100 }; } } From 3ec78388e896e6b5bf1fe1f2fa3869545c6759c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 11:02:54 +0900 Subject: [PATCH 266/966] Avoid excess background updates in playlist overlay --- osu.Game/Overlays/Music/PlaylistList.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 5b528c5ab2..e8c2537c43 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -84,7 +84,7 @@ namespace osu.Game.Overlays.Music beatmaps.ForEach(addBeatmapSet); beatmapBacking.BindTo(beatmap); - beatmapBacking.ValueChanged += _ => updateSelectedSet(); + beatmapBacking.ValueChanged += _ => Scheduler.AddOnce(updateSelectedSet); } private void addBeatmapSet(BeatmapSetInfo obj) From e7fc5e556c79f154b334545b2d367e712c0154e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 10:40:52 +0900 Subject: [PATCH 267/966] Fix song select not correctly playing tracks in some cases --- osu.Game/Screens/Select/SongSelect.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index d9ddfa2a94..04a686f481 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -412,9 +412,6 @@ namespace osu.Game.Screens.Select WorkingBeatmap previous = Beatmap.Value; Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous); - if (this.IsCurrentScreen() && Beatmap.Value?.Track != previous?.Track) - ensurePlayingSelected(true); - if (beatmap != null) { if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) @@ -424,6 +421,9 @@ namespace osu.Game.Screens.Select } } + if (this.IsCurrentScreen()) + ensurePlayingSelected(); + UpdateBeatmap(Beatmap.Value); } } @@ -581,19 +581,14 @@ namespace osu.Game.Screens.Select beatmap.Track.Looping = true; } - private void ensurePlayingSelected(bool restart = false) + private void ensurePlayingSelected() { Track track = Beatmap.Value.Track; - if (!track.IsRunning) - { - track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; + track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; - if (restart) - track.Restart(); - else - track.Start(); - } + if (!track.IsRunning) + track.Restart(); } private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); From 3c0b1be7f48c32db7714b04ce6fda76ffeefdcb8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 11:52:16 +0900 Subject: [PATCH 268/966] Add xmldoc where applicable --- osu.Game/Screens/Menu/IntroScreen.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index c81fef6436..1052ebdd5b 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -21,8 +21,15 @@ namespace osu.Game.Screens.Menu { public abstract class IntroScreen : StartupScreen { + /// + /// A hash used to find the associated beatmap if already imported. + /// protected abstract string BeatmapHash { get; } + /// + /// A source file to use as an import source if the intro beatmap is not yet present. + /// Should be within the "Tracks" namespace of game resources. + /// protected abstract string BeatmapFile { get; } private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); From c3d56088d87d8f12fe7abbe2912b8a6f89e73bc1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 11:54:39 +0900 Subject: [PATCH 269/966] Make constant private --- osu.Game/Screens/Menu/IntroScreen.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 1052ebdd5b..5d560c0c2a 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Menu private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); - public const int EXIT_DELAY = 3000; + private const int exit_delay = 3000; [Resolved] private AudioManager audio { get; set; } @@ -110,7 +110,7 @@ namespace osu.Game.Screens.Menu { this.FadeIn(300); - double fadeOutTime = EXIT_DELAY; + double fadeOutTime = exit_delay; //we also handle the exit transition. if (MenuVoice.Value) seeya.Play(); @@ -151,8 +151,8 @@ namespace osu.Game.Screens.Menu .ScaleTo(1, initialMovementTime, Easing.OutQuint) .FadeIn(quick_appear, Easing.OutQuint) .Then() - .RotateTo(20, EXIT_DELAY * 1.5f) - .FadeOut(EXIT_DELAY); + .RotateTo(20, exit_delay * 1.5f) + .FadeOut(exit_delay); } } From 449e53ee6d5c57db401884b9924eb4d5158dda20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:03:42 +0900 Subject: [PATCH 270/966] Centralise track handling --- osu.Game/Screens/Menu/IntroCircles.cs | 12 +----------- osu.Game/Screens/Menu/IntroScreen.cs | 18 +++++++++++++++++- osu.Game/Screens/Menu/IntroTriangles.cs | 13 +------------ 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index 6c643860a0..8f3b4f43c5 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -30,19 +30,11 @@ namespace osu.Game.Screens.Menu if (!resuming) { - Beatmap.Value = IntroBeatmap; - IntroBeatmap = null; - Welcome?.Play(); Scheduler.AddDelayed(delegate { - // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. - if (MenuMusic.Value) - { - Track.Restart(); - Track = null; - } + StartTrack(); PrepareMenuLoad(); @@ -57,8 +49,6 @@ namespace osu.Game.Screens.Menu public override void OnSuspending(IScreen next) { - Track = null; - this.FadeOut(300); base.OnSuspending(next); } diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 5d560c0c2a..c00d105e12 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Menu protected Bindable MenuMusic; - protected Track Track; + protected Track Track { get; private set; } protected WorkingBeatmap IntroBeatmap; @@ -57,6 +57,13 @@ namespace osu.Game.Screens.Menu protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); + protected void StartTrack() + { + // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. + if (MenuMusic.Value) + Track.Restart(); + } + [BackgroundDependencyLoader] private void load(OsuConfigManager config, SkinManager skinManager, BeatmapManager beatmaps, Framework.Game game) { @@ -136,6 +143,9 @@ namespace osu.Game.Screens.Menu if (!resuming) { + Beatmap.Value = IntroBeatmap; + IntroBeatmap = null; + logo.MoveTo(new Vector2(0.5f)); logo.ScaleTo(Vector2.One); logo.Hide(); @@ -156,6 +166,12 @@ namespace osu.Game.Screens.Menu } } + public override void OnSuspending(IScreen next) + { + base.OnSuspending(next); + Track = null; + } + private MainMenu mainMenu; protected void PrepareMenuLoad() diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 590069ab43..08941eca37 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -55,9 +55,6 @@ namespace osu.Game.Screens.Menu if (!resuming) { - Beatmap.Value = IntroBeatmap; - IntroBeatmap = null; - PrepareMenuLoad(); LoadComponentAsync(new TrianglesIntroSequence(logo, background) @@ -70,9 +67,7 @@ namespace osu.Game.Screens.Menu AddInternal(t); Welcome?.Play(); - // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. - if (MenuMusic.Value) - Track.Start(); + StartTrack(); }); } } @@ -83,12 +78,6 @@ namespace osu.Game.Screens.Menu background.FadeOut(100); } - public override void OnSuspending(IScreen next) - { - Track = null; - base.OnSuspending(next); - } - private class TrianglesIntroSequence : CompositeDrawable { private readonly OsuLogo logo; From a0bb19334219edf1f37282a95aa11893cb2fd954 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:04:13 +0900 Subject: [PATCH 271/966] Remove unnecessary beatmap storage --- osu.Game/Screens/Menu/IntroScreen.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index c00d105e12..ccb7b8ef3d 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -53,8 +53,6 @@ namespace osu.Game.Screens.Menu private LeasedBindable beatmap; - public new Bindable Beatmap => beatmap; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); protected void StartTrack() @@ -68,7 +66,7 @@ namespace osu.Game.Screens.Menu private void load(OsuConfigManager config, SkinManager skinManager, BeatmapManager beatmaps, Framework.Game game) { // prevent user from changing beatmap while the intro is still runnning. - beatmap = base.Beatmap.BeginLease(false); + beatmap = Beatmap.BeginLease(false); MenuVoice = config.GetBindable(OsuSetting.MenuVoice); MenuMusic = config.GetBindable(OsuSetting.MenuMusic); From 4ba2dccde30caac207687d4bff7bbb62a2d770cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:05:52 +0900 Subject: [PATCH 272/966] Reorder file contents --- osu.Game/Screens/Menu/IntroScreen.cs | 73 +++++++++++++--------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index ccb7b8ef3d..c638d4f3c9 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -21,6 +21,11 @@ namespace osu.Game.Screens.Menu { public abstract class IntroScreen : StartupScreen { + /// + /// Whether we have loaded the menu previously. + /// + public bool DidLoadMenu { get; private set; } + /// /// A hash used to find the associated beatmap if already imported. /// @@ -32,35 +37,28 @@ namespace osu.Game.Screens.Menu /// protected abstract string BeatmapFile { get; } - private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); - - private const int exit_delay = 3000; - - [Resolved] - private AudioManager audio { get; set; } - protected SampleChannel Welcome; - private SampleChannel seeya; - protected Bindable MenuVoice; protected Bindable MenuMusic; + protected WorkingBeatmap IntroBeatmap; + protected Track Track { get; private set; } - protected WorkingBeatmap IntroBeatmap; + private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); + + private const int exit_delay = 3000; + + private SampleChannel seeya; private LeasedBindable beatmap; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); + private MainMenu mainMenu; - protected void StartTrack() - { - // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. - if (MenuMusic.Value) - Track.Restart(); - } + [Resolved] + private AudioManager audio { get; set; } [BackgroundDependencyLoader] private void load(OsuConfigManager config, SkinManager skinManager, BeatmapManager beatmaps, Framework.Game game) @@ -100,16 +98,7 @@ namespace osu.Game.Screens.Menu Track = IntroBeatmap.Track; } - /// - /// Whether we have loaded the menu previously. - /// - public bool DidLoadMenu { get; private set; } - - public override bool OnExiting(IScreen next) - { - //cancel exiting if we haven't loaded the menu yet. - return !DidLoadMenu; - } + public override bool OnExiting(IScreen next) => !DidLoadMenu; public override void OnResuming(IScreen last) { @@ -131,6 +120,21 @@ namespace osu.Game.Screens.Menu base.OnResuming(last); } + public override void OnSuspending(IScreen next) + { + base.OnSuspending(next); + Track = null; + } + + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); + + protected void StartTrack() + { + // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. + if (MenuMusic.Value) + Track.Restart(); + } + protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); @@ -151,7 +155,7 @@ namespace osu.Game.Screens.Menu else { const int quick_appear = 350; - int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0; + var initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0; logo.MoveTo(new Vector2(0.5f), initialMovementTime, Easing.OutQuint); @@ -164,18 +168,7 @@ namespace osu.Game.Screens.Menu } } - public override void OnSuspending(IScreen next) - { - base.OnSuspending(next); - Track = null; - } - - private MainMenu mainMenu; - - protected void PrepareMenuLoad() - { - LoadComponentAsync(mainMenu = new MainMenu()); - } + protected void PrepareMenuLoad() => LoadComponentAsync(mainMenu = new MainMenu()); protected void LoadMenu() { From b8b2ff2674001e9bc3334a7799a8931b5004e7d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:07:59 +0900 Subject: [PATCH 273/966] Move welcome to local usages --- osu.Game/Screens/Menu/IntroCircles.cs | 7 +++++-- osu.Game/Screens/Menu/IntroScreen.cs | 2 -- osu.Game/Screens/Menu/IntroTriangles.cs | 7 +++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index 8f3b4f43c5..aa9cee969c 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Screens; using osu.Framework.Graphics; @@ -17,11 +18,13 @@ namespace osu.Game.Screens.Menu private const double delay_step_one = 2300; private const double delay_step_two = 600; + private SampleChannel welcome; + [BackgroundDependencyLoader] private void load(AudioManager audio) { if (MenuVoice.Value) - Welcome = audio.Samples.Get(@"welcome"); + welcome = audio.Samples.Get(@"welcome"); } protected override void LogoArriving(OsuLogo logo, bool resuming) @@ -30,7 +33,7 @@ namespace osu.Game.Screens.Menu if (!resuming) { - Welcome?.Play(); + welcome?.Play(); Scheduler.AddDelayed(delegate { diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index c638d4f3c9..0c192552eb 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -37,8 +37,6 @@ namespace osu.Game.Screens.Menu /// protected abstract string BeatmapFile { get; } - protected SampleChannel Welcome; - protected Bindable MenuVoice; protected Bindable MenuMusic; diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 08941eca37..c86f1393a4 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Screens; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -40,11 +41,13 @@ namespace osu.Game.Screens.Menu private BackgroundScreenDefault background; + private SampleChannel welcome; + [BackgroundDependencyLoader] private void load(AudioManager audio) { if (MenuVoice.Value && !MenuMusic.Value) - Welcome = audio.Samples.Get(@"welcome"); + welcome = audio.Samples.Get(@"welcome"); } protected override void LogoArriving(OsuLogo logo, bool resuming) @@ -65,7 +68,7 @@ namespace osu.Game.Screens.Menu }, t => { AddInternal(t); - Welcome?.Play(); + welcome?.Play(); StartTrack(); }); From c280bee894df7e9c01c88332df579d2964f401e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:08:47 +0900 Subject: [PATCH 274/966] Protect configuration bindables --- osu.Game/Screens/Menu/IntroScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 0c192552eb..feb472ba88 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -37,9 +37,9 @@ namespace osu.Game.Screens.Menu /// protected abstract string BeatmapFile { get; } - protected Bindable MenuVoice; + protected IBindable MenuVoice { get; private set; } - protected Bindable MenuMusic; + protected IBindable MenuMusic { get; private set; } protected WorkingBeatmap IntroBeatmap; From cbb120cd3874044673e3197a9fc78942433a3edd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:09:42 +0900 Subject: [PATCH 275/966] Switch beatmap to private --- osu.Game/Screens/Menu/IntroScreen.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index feb472ba88..f5ef839b06 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Menu protected IBindable MenuMusic { get; private set; } - protected WorkingBeatmap IntroBeatmap; + private WorkingBeatmap introBeatmap; protected Track Track { get; private set; } @@ -92,8 +92,8 @@ namespace osu.Game.Screens.Menu } } - IntroBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); - Track = IntroBeatmap.Track; + introBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); + Track = introBeatmap.Track; } public override bool OnExiting(IScreen next) => !DidLoadMenu; @@ -143,8 +143,8 @@ namespace osu.Game.Screens.Menu if (!resuming) { - Beatmap.Value = IntroBeatmap; - IntroBeatmap = null; + Beatmap.Value = introBeatmap; + introBeatmap = null; logo.MoveTo(new Vector2(0.5f)); logo.ScaleTo(Vector2.One); From 52770f803d8844c135c3cfb05a4abb1d119e087c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:14:53 +0900 Subject: [PATCH 276/966] Fix incorrect beatmap usage --- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index f5ef839b06..df83e98494 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -143,7 +143,7 @@ namespace osu.Game.Screens.Menu if (!resuming) { - Beatmap.Value = introBeatmap; + beatmap.Value = introBeatmap; introBeatmap = null; logo.MoveTo(new Vector2(0.5f)); From 5472029ffed6681a327eeacad42577da0306e0e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:27:51 +0900 Subject: [PATCH 277/966] Fix editor defaulting to 0.5x playback speed --- osu.Game/Screens/Edit/Components/PlaybackControl.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 8d4ad0efa9..62d6c4648b 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -105,6 +106,8 @@ namespace osu.Game.Screens.Edit.Components TabContainer.Spacing = Vector2.Zero; tempo_values.ForEach(AddItem); + + Current.Value = tempo_values.Last(); } public class PlaybackTabItem : TabItem From 24269c0384f6ebaa5c09ce52c6a4d404bf23fb7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:52:34 +0900 Subject: [PATCH 278/966] Fix skins not being displayed correctly in the editor --- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 13 ++++++++++++- osu.Game/Skinning/SkinProvidingContainer.cs | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index ec4dda5c23..bd7e8e44e5 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Logging; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osu.Game.Skinning; using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose @@ -115,7 +116,17 @@ namespace osu.Game.Screens.Edit.Compose return; } - composerContainer.Child = composer; + var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); + + // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation + // full access to all skin sources. + var rulesetSkinProvider = new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(beatmapSkinProvider)); + + // load the skinning hierarchy first. + // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. + composerContainer.Add( + beatmapSkinProvider.WithChild( + rulesetSkinProvider.WithChild(composer))); } } } diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index ef7f5f381b..1c01bbf1ab 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -53,7 +53,7 @@ namespace osu.Game.Skinning if (AllowTextureLookup(componentName) && (sourceTexture = skin?.GetTexture(componentName)) != null) return sourceTexture; - return fallbackSource.GetTexture(componentName); + return fallbackSource?.GetTexture(componentName); } public SampleChannel GetSample(ISampleInfo sampleInfo) From 63bf8ff832ba04886bb2b60f83247f4b30e3073d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 14:23:13 +0900 Subject: [PATCH 279/966] Better signify under construction screens in editor --- .../Screens/Edit/Compose/ComposeScreen.cs | 41 ++-- osu.Game/Screens/Edit/Design/DesignScreen.cs | 41 +--- osu.Game/Screens/Edit/Editor.cs | 10 + osu.Game/Screens/Edit/Setup/SetupScreen.cs | 13 ++ osu.Game/Screens/Edit/Timing/SetupScreen.cs | 13 ++ osu.Game/Screens/ScreenWhiteBox.cs | 200 ++++++++++-------- 6 files changed, 169 insertions(+), 149 deletions(-) create mode 100644 osu.Game/Screens/Edit/Setup/SetupScreen.cs create mode 100644 osu.Game/Screens/Edit/Timing/SetupScreen.cs diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index bd7e8e44e5..2a99d81516 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; -using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Skinning; @@ -23,8 +22,6 @@ namespace osu.Game.Screens.Edit.Compose private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - private HitObjectComposer composer; - [BackgroundDependencyLoader(true)] private void load([CanBeNull] BindableBeatDivisor beatDivisor) { @@ -107,26 +104,32 @@ namespace osu.Game.Screens.Edit.Compose return; } - composer = ruleset.CreateHitObjectComposer(); + var composer = ruleset.CreateHitObjectComposer(); - if (composer == null) + Drawable content; + + if (composer != null) { - Logger.Log($"Ruleset {ruleset.Description} doesn't support hitobject composition."); - // ExitRequested?.Invoke(); - return; + var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); + + // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation + // full access to all skin sources. + var rulesetSkinProvider = new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(beatmapSkinProvider)); + + // load the skinning hierarchy first. + // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. + content = beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); + } + else + { + content = new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); } - var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); - - // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation - // full access to all skin sources. - var rulesetSkinProvider = new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(beatmapSkinProvider)); - - // load the skinning hierarchy first. - // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. - composerContainer.Add( - beatmapSkinProvider.WithChild( - rulesetSkinProvider.WithChild(composer))); + LoadComponentAsync(content, _ => + { + composerContainer.Add(content); + content.FadeInFromZero(300, Easing.OutQuint); + }); } } } diff --git a/osu.Game/Screens/Edit/Design/DesignScreen.cs b/osu.Game/Screens/Edit/Design/DesignScreen.cs index 2a334e1b30..9f1fcf55b2 100644 --- a/osu.Game/Screens/Edit/Design/DesignScreen.cs +++ b/osu.Game/Screens/Edit/Design/DesignScreen.cs @@ -1,52 +1,13 @@ // 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; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Sprites; -using osuTK.Graphics; - namespace osu.Game.Screens.Edit.Design { public class DesignScreen : EditorScreen { public DesignScreen() { - Add(new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.35f - }, - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f - }, - new Container - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(20), - Child = new OsuSpriteText { Text = "Design screen" } - } - } - } - } - }); + Child = new ScreenWhiteBox.UnderConstructionMessage("Design mode"); } } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 8cc227d9be..9ebe3bc26a 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -26,6 +26,8 @@ using System.Collections.Generic; using osu.Framework; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; +using osu.Game.Screens.Edit.Setup; +using osu.Game.Screens.Edit.Timing; using osu.Game.Users; namespace osu.Game.Screens.Edit @@ -258,6 +260,10 @@ namespace osu.Game.Screens.Edit switch (e.NewValue) { + case EditorScreenMode.SongSetup: + currentScreen = new SetupScreen(); + break; + case EditorScreenMode.Compose: currentScreen = new ComposeScreen(); break; @@ -266,6 +272,10 @@ namespace osu.Game.Screens.Edit currentScreen = new DesignScreen(); break; + case EditorScreenMode.Timing: + currentScreen = new TimingScreen(); + break; + default: currentScreen = new EditorScreen(); break; diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs new file mode 100644 index 0000000000..758dbc6e16 --- /dev/null +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.Edit.Setup +{ + public class SetupScreen : EditorScreen + { + public SetupScreen() + { + Child = new ScreenWhiteBox.UnderConstructionMessage("Setup mode"); + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/SetupScreen.cs b/osu.Game/Screens/Edit/Timing/SetupScreen.cs new file mode 100644 index 0000000000..9ded4207e5 --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/SetupScreen.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.Edit.Timing +{ + public class TimingScreen : EditorScreen + { + public TimingScreen() + { + Child = new ScreenWhiteBox.UnderConstructionMessage("Timing mode"); + } + } +} diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs index 6c5854d17e..e4971221c4 100644 --- a/osu.Game/Screens/ScreenWhiteBox.cs +++ b/osu.Game/Screens/ScreenWhiteBox.cs @@ -20,38 +20,17 @@ namespace osu.Game.Screens { public class ScreenWhiteBox : OsuScreen { + private readonly UnderConstructionMessage message; + private const double transition_time = 1000; protected virtual IEnumerable PossibleChildren => null; - private readonly FillFlowContainer textContainer; - private readonly Container boxContainer; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg2"); - public override void OnEntering(IScreen last) - { - base.OnEntering(last); - - Alpha = 0; - textContainer.Position = new Vector2(DrawSize.X / 16, 0); - - boxContainer.ScaleTo(0.2f); - boxContainer.RotateTo(-20); - - using (BeginDelayedSequence(300, true)) - { - boxContainer.ScaleTo(1, transition_time, Easing.OutElastic); - boxContainer.RotateTo(0, transition_time / 2, Easing.OutQuint); - - textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); - this.FadeIn(transition_time, Easing.OutExpo); - } - } - public override bool OnExiting(IScreen next) { - textContainer.MoveTo(new Vector2(DrawSize.X / 16, 0), transition_time, Easing.OutExpo); + message.TextContainer.MoveTo(new Vector2(DrawSize.X / 16, 0), transition_time, Easing.OutExpo); this.FadeOut(transition_time, Easing.OutExpo); return base.OnExiting(next); @@ -61,7 +40,7 @@ namespace osu.Game.Screens { base.OnSuspending(next); - textContainer.MoveTo(new Vector2(-(DrawSize.X / 16), 0), transition_time, Easing.OutExpo); + message.TextContainer.MoveTo(new Vector2(-(DrawSize.X / 16), 0), transition_time, Easing.OutExpo); this.FadeOut(transition_time, Easing.OutExpo); } @@ -69,7 +48,7 @@ namespace osu.Game.Screens { base.OnResuming(last); - textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); + message.TextContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); this.FadeIn(transition_time, Easing.OutExpo); } @@ -79,65 +58,7 @@ namespace osu.Game.Screens InternalChildren = new Drawable[] { - boxContainer = new Container - { - Size = new Vector2(0.3f), - RelativeSizeAxes = Axes.Both, - CornerRadius = 20, - Masking = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - - Colour = getColourFor(GetType()), - Alpha = 0.2f, - Blending = BlendingParameters.Additive, - }, - textContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.UniversalAccess, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(50), - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = GetType().Name, - Colour = getColourFor(GetType()).Lighten(0.8f), - Font = OsuFont.GetFont(size: 50), - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "is not yet ready for use!", - Font = OsuFont.GetFont(size: 20), - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "please check back a bit later.", - Font = OsuFont.GetFont(size: 14), - }, - } - }, - } - }, + message = new UnderConstructionMessage(GetType().Name), childModeButtons = new FillFlowContainer { Direction = FillDirection.Vertical, @@ -155,24 +76,24 @@ namespace osu.Game.Screens childModeButtons.Add(new ChildModeButton { Text = $@"{t.Name}", - BackgroundColour = getColourFor(t), - HoverColour = getColourFor(t).Lighten(0.2f), + BackgroundColour = getColourFor(t.Name), + HoverColour = getColourFor(t.Name).Lighten(0.2f), Action = delegate { this.Push(Activator.CreateInstance(t) as Screen); } }); } } } - private Color4 getColourFor(Type type) + private static Color4 getColourFor(object type) { - int hash = type.Name.GetHashCode(); + int hash = type.GetHashCode(); byte r = (byte)MathHelper.Clamp(((hash & 0xFF0000) >> 16) * 0.8f, 20, 255); byte g = (byte)MathHelper.Clamp(((hash & 0x00FF00) >> 8) * 0.8f, 20, 255); byte b = (byte)MathHelper.Clamp((hash & 0x0000FF) * 0.8f, 20, 255); return new Color4(r, g, b, 255); } - public class ChildModeButton : TwoLayerButton + private class ChildModeButton : TwoLayerButton { public ChildModeButton() { @@ -181,5 +102,104 @@ namespace osu.Game.Screens Origin = Anchor.BottomRight; } } + + public class UnderConstructionMessage : CompositeDrawable + { + public FillFlowContainer TextContainer { get; } + + private readonly Container boxContainer; + + public UnderConstructionMessage(string name) + { + RelativeSizeAxes = Axes.Both; + Size = new Vector2(0.3f); + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + var colour = getColourFor(name); + + InternalChildren = new Drawable[] + { + boxContainer = new Container + { + CornerRadius = 20, + Masking = true, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + + Colour = colour, + Alpha = 0.2f, + Blending = BlendingParameters.Additive, + }, + TextContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.UniversalAccess, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(50), + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = name, + Colour = colour.Lighten(0.8f), + Font = OsuFont.GetFont(size: 36), + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "is not yet ready for use!", + Font = OsuFont.GetFont(size: 20), + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "please check back a bit later.", + Font = OsuFont.GetFont(size: 14), + }, + } + }, + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + TextContainer.Position = new Vector2(DrawSize.X / 16, 0); + + boxContainer.Hide(); + boxContainer.ScaleTo(0.2f); + boxContainer.RotateTo(-20); + + using (BeginDelayedSequence(300, true)) + { + boxContainer.ScaleTo(1, transition_time, Easing.OutElastic); + boxContainer.RotateTo(0, transition_time / 2, Easing.OutQuint); + + TextContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); + boxContainer.FadeIn(transition_time, Easing.OutExpo); + } + } + } } } From 3e904b4838b9169b80b0f6fc2381f0de6a47a6cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 14:37:56 +0900 Subject: [PATCH 280/966] Fix naming of file --- osu.Game/Screens/Edit/Timing/{SetupScreen.cs => TimingScreen.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Screens/Edit/Timing/{SetupScreen.cs => TimingScreen.cs} (100%) diff --git a/osu.Game/Screens/Edit/Timing/SetupScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs similarity index 100% rename from osu.Game/Screens/Edit/Timing/SetupScreen.cs rename to osu.Game/Screens/Edit/Timing/TimingScreen.cs From 4e026b163ccd15556945a8d769cad3b5c0a8ac34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 15:03:48 +0900 Subject: [PATCH 281/966] Don't resume playback when user has paused and track hasn't changed --- osu.Game/Screens/Select/SongSelect.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 04a686f481..6c5f64ed6c 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -581,14 +581,24 @@ namespace osu.Game.Screens.Select beatmap.Track.Looping = true; } + private readonly WeakReference lastTrack = new WeakReference(null); + + /// + /// Ensures some music is playing for the current track. + /// Will resume playback from a manual user pause if the track has changed. + /// private void ensurePlayingSelected() { Track track = Beatmap.Value.Track; + bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; + track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; - if (!track.IsRunning) + if (!track.IsRunning && (music?.IsUserPaused != true || isNewTrack)) track.Restart(); + + lastTrack.SetTarget(track); } private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); From f284d096b75fc63349f08fa0385ce8709e79f214 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 16:37:47 +0900 Subject: [PATCH 282/966] Fix ignored song select test --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 263eada07c..be054495cc 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -128,12 +128,10 @@ namespace osu.Game.Tests.Visual.SongSelect } [Test] - [Ignore("needs fixing")] public void TestImportUnderDifferentRuleset() { createSongSelect(); - changeRuleset(2); - addRulesetImportStep(0); + addRulesetImportStep(2); AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmap == null); } From 8ebccfe31fe098807ed355bf171c990557d6642f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 16:37:34 +0900 Subject: [PATCH 283/966] Add comprehensive audio state tests --- .../SongSelect/TestScenePlaySongSelect.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 263eada07c..5584de5484 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -16,6 +16,7 @@ using osu.Framework.Platform; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -34,6 +35,8 @@ namespace osu.Game.Tests.Visual.SongSelect private RulesetStore rulesets; + private MusicController music; + private WorkingBeatmap defaultBeatmap; public override IReadOnlyList RequiredTypes => new[] @@ -79,6 +82,11 @@ namespace osu.Game.Tests.Visual.SongSelect Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default)); + Dependencies.Cache(music = new MusicController()); + + // required to get bindables attached + Add(music); + Beatmap.SetDefault(); Dependencies.Cache(config = new OsuConfigManager(LocalStorage)); @@ -93,6 +101,57 @@ namespace osu.Game.Tests.Visual.SongSelect manager?.Delete(manager.GetAllUsableBeatmapSets()); }); + [Test] + public void TestAudioResuming() + { + createSongSelect(); + + addRulesetImportStep(0); + addRulesetImportStep(0); + + checkMusicPlaying(true); + AddStep("select first", () => songSelect.Carousel.SelectBeatmap(songSelect.Carousel.BeatmapSets.First().Beatmaps.First())); + checkMusicPlaying(true); + + AddStep("manual pause", () => music.TogglePause()); + checkMusicPlaying(false); + AddStep("select next difficulty", () => songSelect.Carousel.SelectNext(skipDifficulties: false)); + checkMusicPlaying(false); + + AddStep("select next set", () => songSelect.Carousel.SelectNext()); + checkMusicPlaying(true); + } + + [TestCase(false)] + [TestCase(true)] + public void TestAudioRemainsCorrectOnRulesetChange(bool rulesetsInSameBeatmap) + { + createSongSelect(); + + // start with non-osu! to avoid convert confusion + changeRuleset(1); + + if (rulesetsInSameBeatmap) + AddStep("import multi-ruleset map", () => + { + var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); + manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait(); + }); + else + { + addRulesetImportStep(1); + addRulesetImportStep(0); + } + + checkMusicPlaying(true); + + AddStep("manual pause", () => music.TogglePause()); + checkMusicPlaying(false); + + changeRuleset(0); + checkMusicPlaying(!rulesetsInSameBeatmap); + } + [Test] public void TestDummy() { @@ -224,6 +283,9 @@ namespace osu.Game.Tests.Visual.SongSelect private static int importId; private int getImportId() => ++importId; + private void checkMusicPlaying(bool playing) => + AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing); + private void changeMods(params Mod[] mods) => AddStep($"change mods to {string.Join(", ", mods.Select(m => m.Acronym))}", () => Mods.Value = mods); private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id)); From b09d9b7e1f761e9070c0f3aa3629928729c1c7a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 17:56:56 +0900 Subject: [PATCH 284/966] Add todo in slider tail to avoid confusion --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index 23c5494cf5..42bf5e4d21 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables positionBindable.BindValueChanged(_ => updatePosition()); pathBindable.BindValueChanged(_ => updatePosition(), true); + + // TODO: This has no drawable content. Support for skins should be added. } protected override void CheckForResult(bool userTriggered, double timeOffset) From 4446a2972c7c36e48099b99fc597587156cf50c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 18:08:05 +0900 Subject: [PATCH 285/966] Move WaveContainer test out of editor namespace --- .../Visual/{Editor => UserInterface}/TestSceneWaveContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game.Tests/Visual/{Editor => UserInterface}/TestSceneWaveContainer.cs (97%) diff --git a/osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs similarity index 97% rename from osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs index de19727251..5b130b9224 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; using osuTK; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.Editor +namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] public class TestSceneWaveContainer : OsuTestScene From 08d043f44715b02f1f65ecdc59fe21ce6190ec2a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 8 Oct 2019 18:57:03 +0900 Subject: [PATCH 286/966] Move selection relative to the hitobject start positions --- .../Blueprints/ManiaSelectionBlueprint.cs | 2 +- .../Edit/ManiaSelectionHandler.cs | 23 ++++---- .../Edit/OsuSelectionHandler.cs | 5 +- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 11 +++- .../Compose/Components/BlueprintContainer.cs | 9 +++- .../Compose/Components/SelectionDragEvent.cs | 53 +++++++++++++++++++ .../Compose/Components/SelectionHandler.cs | 2 +- 7 files changed, 87 insertions(+), 18 deletions(-) create mode 100644 osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs index d3c12b1944..cc50459a0c 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints public Vector2 ScreenSpaceDragPosition { get; private set; } public Vector2 DragPosition { get; private set; } - protected new DrawableManiaHitObject HitObject => (DrawableManiaHitObject)base.HitObject; + public new DrawableManiaHitObject HitObject => (DrawableManiaHitObject)base.HitObject; protected IClock EditorClock { get; private set; } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 6f49c7f0c4..389837b059 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -3,7 +3,6 @@ using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; @@ -31,11 +30,14 @@ namespace osu.Game.Rulesets.Mania.Edit editorClock = clock; } - public override void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent) + public override void HandleDrag(SelectionBlueprint blueprint, SelectionDragEvent dragEvent) { - adjustOrigins((ManiaSelectionBlueprint)blueprint); + var maniaBlueprint = (ManiaSelectionBlueprint)blueprint; + int lastColumn = maniaBlueprint.HitObject.HitObject.Column; + + adjustOrigins(maniaBlueprint); performDragMovement(dragEvent); - performColumnMovement(dragEvent); + performColumnMovement(lastColumn, dragEvent); base.HandleDrag(blueprint, dragEvent); } @@ -62,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Edit b.HitObject.Y += movementDelta; } - private void performDragMovement(DragEvent dragEvent) + private void performDragMovement(SelectionDragEvent dragEvent) { foreach (var b in SelectedBlueprints) { @@ -72,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Edit // Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame // without the position having been updated by the parenting ScrollingHitObjectContainer - hitObject.Y += dragEvent.Delta.Y; + hitObject.Y += dragEvent.InstantDragDelta.Y; float targetPosition; @@ -94,14 +96,13 @@ namespace osu.Game.Rulesets.Mania.Edit } } - private void performColumnMovement(DragEvent dragEvent) + private void performColumnMovement(int lastColumn, SelectionDragEvent dragEvent) { - var lastColumn = composer.ColumnAt(dragEvent.ScreenSpaceLastMousePosition); - var currentColumn = composer.ColumnAt(dragEvent.ScreenSpaceMousePosition); - if (lastColumn == null || currentColumn == null) + var currentColumn = composer.ColumnAt(dragEvent.ScreenSpaceDragPosition); + if (currentColumn == null) return; - int columnDelta = currentColumn.Index - lastColumn.Index; + int columnDelta = currentColumn.Index - lastColumn; if (columnDelta == 0) return; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 1ab1219ab0..4a0e88889b 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -11,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Edit { public class OsuSelectionHandler : SelectionHandler { - public override void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent) + public override void HandleDrag(SelectionBlueprint blueprint, SelectionDragEvent dragEvent) { foreach (var h in SelectedHitObjects.OfType()) { @@ -21,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Edit continue; } - h.Position += dragEvent.Delta; + h.Position += dragEvent.InstantDragDelta; } base.HandleDrag(blueprint, dragEvent); diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 0f77b8d584..aa0dd1cc25 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -45,6 +45,11 @@ namespace osu.Game.Rulesets.Edit /// public readonly DrawableHitObject HitObject; + /// + /// The screen-space position of when a drag was started. + /// + public Vector2 ScreenSpaceDragStartPosition { get; private set; } + protected override bool ShouldBeAlive => (HitObject.IsAlive && HitObject.IsPresent) || State == SelectionState.Selected; public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; @@ -131,7 +136,11 @@ namespace osu.Game.Rulesets.Edit return base.OnClick(e); } - protected override bool OnDragStart(DragStartEvent e) => true; + protected override bool OnDragStart(DragStartEvent e) + { + ScreenSpaceDragStartPosition = HitObject.ToScreenSpace(HitObject.OriginPosition); + return true; + } protected override bool OnDrag(DragEvent e) { diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index d96d88c2b9..3286be4be6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -216,7 +216,14 @@ namespace osu.Game.Screens.Edit.Compose.Components private void onSelectionRequested(SelectionBlueprint blueprint, InputState state) => selectionHandler.HandleSelectionRequested(blueprint, state); - private void onDragRequested(SelectionBlueprint blueprint, DragEvent dragEvent) => selectionHandler.HandleDrag(blueprint, dragEvent); + private void onDragRequested(SelectionBlueprint blueprint, DragEvent dragEvent) + { + var dragPosition = blueprint.ScreenSpaceDragStartPosition + dragEvent.ScreenSpaceMousePosition - dragEvent.ScreenSpaceMouseDownPosition; + + // Todo: Snap dragPosition + + selectionHandler.HandleDrag(blueprint, new SelectionDragEvent(blueprint, blueprint.ScreenSpaceDragStartPosition, dragPosition)); + } protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs new file mode 100644 index 0000000000..8e00e8c30c --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Edit; +using osuTK; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + /// + /// An event which occurs when a is dragged. + /// + public class SelectionDragEvent + { + /// + /// The dragged . + /// + public readonly SelectionBlueprint DraggedBlueprint; + + /// + /// The screen-space position of the hitobject at the start of the drag. + /// + public readonly Vector2 ScreenSpaceDragStartPosition; + + /// + /// The new screen-space position of the hitobject at the current drag point. + /// + public readonly Vector2 ScreenSpaceDragPosition; + + /// + /// The distance between and the hitobject's current position, in the coordinate-space of the hitobject's parent. + /// + /// + /// This does not use and does not represent the cumulative drag distance. + /// + public readonly Vector2 InstantDragDelta; + + public SelectionDragEvent(SelectionBlueprint blueprint, Vector2 screenSpaceDragStartPosition, Vector2 screenSpaceDragPosition) + { + DraggedBlueprint = blueprint; + ScreenSpaceDragStartPosition = screenSpaceDragStartPosition; + ScreenSpaceDragPosition = screenSpaceDragPosition; + + InstantDragDelta = toLocalSpace(ScreenSpaceDragPosition) - DraggedBlueprint.HitObject.Position; + } + + /// + /// Converts a screen-space position into the coordinate space of the hitobject's parents. + /// + /// The screen-space position. + /// The position in the coordinate space of the hitobject's parent. + private Vector2 toLocalSpace(Vector2 screenSpacePosition) => DraggedBlueprint.HitObject.Parent.ToLocalSpace(screenSpacePosition); + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 11e649168f..3fb06c8ee8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -69,7 +69,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// The that received the drag event. /// The drag event. - public virtual void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent) + public virtual void HandleDrag(SelectionBlueprint blueprint, SelectionDragEvent dragEvent) { } From 8b661e624d25334b7c1b67db6b6c83c138a51ec1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 8 Oct 2019 19:08:23 +0900 Subject: [PATCH 287/966] Remove drag from class/method namings + refactor --- .../Edit/ManiaSelectionHandler.cs | 19 ++++--- .../Edit/OsuSelectionHandler.cs | 7 ++- .../Compose/Components/BlueprintContainer.cs | 2 +- .../Compose/Components/MoveSelectionEvent.cs | 53 +++++++++++++++++++ .../Compose/Components/SelectionDragEvent.cs | 53 ------------------- .../Compose/Components/SelectionHandler.cs | 7 ++- 6 files changed, 69 insertions(+), 72 deletions(-) create mode 100644 osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs delete mode 100644 osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 389837b059..f576c43e52 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -4,7 +4,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Timing; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.UI; @@ -30,16 +29,16 @@ namespace osu.Game.Rulesets.Mania.Edit editorClock = clock; } - public override void HandleDrag(SelectionBlueprint blueprint, SelectionDragEvent dragEvent) + public override void HandleMovement(MoveSelectionEvent moveEvent) { - var maniaBlueprint = (ManiaSelectionBlueprint)blueprint; + var maniaBlueprint = (ManiaSelectionBlueprint)moveEvent.Blueprint; int lastColumn = maniaBlueprint.HitObject.HitObject.Column; adjustOrigins(maniaBlueprint); - performDragMovement(dragEvent); - performColumnMovement(lastColumn, dragEvent); + performDragMovement(moveEvent); + performColumnMovement(lastColumn, moveEvent); - base.HandleDrag(blueprint, dragEvent); + base.HandleMovement(moveEvent); } /// @@ -64,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.Edit b.HitObject.Y += movementDelta; } - private void performDragMovement(SelectionDragEvent dragEvent) + private void performDragMovement(MoveSelectionEvent moveEvent) { foreach (var b in SelectedBlueprints) { @@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.Edit // Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame // without the position having been updated by the parenting ScrollingHitObjectContainer - hitObject.Y += dragEvent.InstantDragDelta.Y; + hitObject.Y += moveEvent.InstantDelta.Y; float targetPosition; @@ -96,9 +95,9 @@ namespace osu.Game.Rulesets.Mania.Edit } } - private void performColumnMovement(int lastColumn, SelectionDragEvent dragEvent) + private void performColumnMovement(int lastColumn, MoveSelectionEvent moveEvent) { - var currentColumn = composer.ColumnAt(dragEvent.ScreenSpaceDragPosition); + var currentColumn = composer.ColumnAt(moveEvent.ScreenSpacePosition); if (currentColumn == null) return; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 4a0e88889b..472267eb66 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Edit { public class OsuSelectionHandler : SelectionHandler { - public override void HandleDrag(SelectionBlueprint blueprint, SelectionDragEvent dragEvent) + public override void HandleMovement(MoveSelectionEvent moveEvent) { foreach (var h in SelectedHitObjects.OfType()) { @@ -20,10 +19,10 @@ namespace osu.Game.Rulesets.Osu.Edit continue; } - h.Position += dragEvent.InstantDragDelta; + h.Position += moveEvent.InstantDelta; } - base.HandleDrag(blueprint, dragEvent); + base.HandleMovement(moveEvent); } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 3286be4be6..593d70b24f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Edit.Compose.Components // Todo: Snap dragPosition - selectionHandler.HandleDrag(blueprint, new SelectionDragEvent(blueprint, blueprint.ScreenSpaceDragStartPosition, dragPosition)); + selectionHandler.HandleMovement(new MoveSelectionEvent(blueprint, blueprint.ScreenSpaceDragStartPosition, dragPosition)); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs b/osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs new file mode 100644 index 0000000000..a75226d2bc --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Edit; +using osuTK; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + /// + /// An event which occurs when a is moved. + /// + public class MoveSelectionEvent + { + /// + /// The that triggered this . + /// + public readonly SelectionBlueprint Blueprint; + + /// + /// The starting screen-space position of the hitobject. + /// + public readonly Vector2 ScreenSpaceStartPosition; + + /// + /// The expected screen-space position of the hitobject at the current cursor position. + /// + public readonly Vector2 ScreenSpacePosition; + + /// + /// The distance between and the hitobject's current position, in the coordinate-space of the hitobject's parent. + /// + /// + /// This does not use and does not represent the cumulative movement distance. + /// + public readonly Vector2 InstantDelta; + + public MoveSelectionEvent(SelectionBlueprint blueprint, Vector2 screenSpaceStartPosition, Vector2 screenSpacePosition) + { + Blueprint = blueprint; + ScreenSpaceStartPosition = screenSpaceStartPosition; + ScreenSpacePosition = screenSpacePosition; + + InstantDelta = toLocalSpace(ScreenSpacePosition) - Blueprint.HitObject.Position; + } + + /// + /// Converts a screen-space position into the coordinate space of the hitobject's parents. + /// + /// The screen-space position. + /// The position in the coordinate space of the hitobject's parent. + private Vector2 toLocalSpace(Vector2 screenSpacePosition) => Blueprint.HitObject.Parent.ToLocalSpace(screenSpacePosition); + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs deleted file mode 100644 index 8e00e8c30c..0000000000 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionDragEvent.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Edit; -using osuTK; - -namespace osu.Game.Screens.Edit.Compose.Components -{ - /// - /// An event which occurs when a is dragged. - /// - public class SelectionDragEvent - { - /// - /// The dragged . - /// - public readonly SelectionBlueprint DraggedBlueprint; - - /// - /// The screen-space position of the hitobject at the start of the drag. - /// - public readonly Vector2 ScreenSpaceDragStartPosition; - - /// - /// The new screen-space position of the hitobject at the current drag point. - /// - public readonly Vector2 ScreenSpaceDragPosition; - - /// - /// The distance between and the hitobject's current position, in the coordinate-space of the hitobject's parent. - /// - /// - /// This does not use and does not represent the cumulative drag distance. - /// - public readonly Vector2 InstantDragDelta; - - public SelectionDragEvent(SelectionBlueprint blueprint, Vector2 screenSpaceDragStartPosition, Vector2 screenSpaceDragPosition) - { - DraggedBlueprint = blueprint; - ScreenSpaceDragStartPosition = screenSpaceDragStartPosition; - ScreenSpaceDragPosition = screenSpaceDragPosition; - - InstantDragDelta = toLocalSpace(ScreenSpaceDragPosition) - DraggedBlueprint.HitObject.Position; - } - - /// - /// Converts a screen-space position into the coordinate space of the hitobject's parents. - /// - /// The screen-space position. - /// The position in the coordinate space of the hitobject's parent. - private Vector2 toLocalSpace(Vector2 screenSpacePosition) => DraggedBlueprint.HitObject.Parent.ToLocalSpace(screenSpacePosition); - } -} diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 3fb06c8ee8..c9e862d99e 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -65,11 +65,10 @@ namespace osu.Game.Screens.Edit.Compose.Components #region User Input Handling /// - /// Handles the selected s being dragged. + /// Handles the selected s being moved. /// - /// The that received the drag event. - /// The drag event. - public virtual void HandleDrag(SelectionBlueprint blueprint, SelectionDragEvent dragEvent) + /// The move event. + public virtual void HandleMovement(MoveSelectionEvent moveEvent) { } From c1db11fa0612622cce5182a987847dc96701e66b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 8 Oct 2019 19:24:58 +0900 Subject: [PATCH 288/966] More removal of "drag" --- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 6 +++--- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index aa0dd1cc25..838984b223 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -46,9 +46,9 @@ namespace osu.Game.Rulesets.Edit public readonly DrawableHitObject HitObject; /// - /// The screen-space position of when a drag was started. + /// The screen-space position of prior to handling a movement event. /// - public Vector2 ScreenSpaceDragStartPosition { get; private set; } + internal Vector2 ScreenSpaceMovementStartPosition { get; private set; } protected override bool ShouldBeAlive => (HitObject.IsAlive && HitObject.IsPresent) || State == SelectionState.Selected; public override bool HandlePositionalInput => ShouldBeAlive; @@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Edit protected override bool OnDragStart(DragStartEvent e) { - ScreenSpaceDragStartPosition = HitObject.ToScreenSpace(HitObject.OriginPosition); + ScreenSpaceMovementStartPosition = HitObject.ToScreenSpace(HitObject.OriginPosition); return true; } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 593d70b24f..2de5ecf633 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -218,11 +218,9 @@ namespace osu.Game.Screens.Edit.Compose.Components private void onDragRequested(SelectionBlueprint blueprint, DragEvent dragEvent) { - var dragPosition = blueprint.ScreenSpaceDragStartPosition + dragEvent.ScreenSpaceMousePosition - dragEvent.ScreenSpaceMouseDownPosition; + var movePosition = blueprint.ScreenSpaceMovementStartPosition + dragEvent.ScreenSpaceMousePosition - dragEvent.ScreenSpaceMouseDownPosition; - // Todo: Snap dragPosition - - selectionHandler.HandleMovement(new MoveSelectionEvent(blueprint, blueprint.ScreenSpaceDragStartPosition, dragPosition)); + selectionHandler.HandleMovement(new MoveSelectionEvent(blueprint, blueprint.ScreenSpaceMovementStartPosition, movePosition)); } protected override void Dispose(bool isDisposing) From 179656788dd87caae95c35c3e8e4b0372106bcbd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 8 Oct 2019 19:27:59 +0900 Subject: [PATCH 289/966] Remove unnecessary method --- .../Edit/Compose/Components/MoveSelectionEvent.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs b/osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs index a75226d2bc..13945381bb 100644 --- a/osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs +++ b/osu.Game/Screens/Edit/Compose/Components/MoveSelectionEvent.cs @@ -40,14 +40,7 @@ namespace osu.Game.Screens.Edit.Compose.Components ScreenSpaceStartPosition = screenSpaceStartPosition; ScreenSpacePosition = screenSpacePosition; - InstantDelta = toLocalSpace(ScreenSpacePosition) - Blueprint.HitObject.Position; + InstantDelta = Blueprint.HitObject.Parent.ToLocalSpace(ScreenSpacePosition) - Blueprint.HitObject.Position; } - - /// - /// Converts a screen-space position into the coordinate space of the hitobject's parents. - /// - /// The screen-space position. - /// The position in the coordinate space of the hitobject's parent. - private Vector2 toLocalSpace(Vector2 screenSpacePosition) => Blueprint.HitObject.Parent.ToLocalSpace(screenSpacePosition); } } From 4b1a40dabaebadb49d07cbc077d71709714fe6d8 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 13:31:49 +0300 Subject: [PATCH 290/966] Implement temp fix to get the actual message --- osu.Game/Online/API/Requests/Responses/Comment.cs | 6 ++++++ osu.Game/Overlays/CommentsContainer.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e4b66ddeee..ba71faa843 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -76,5 +76,11 @@ namespace osu.Game.Online.API.Requests.Responses public bool IsTopLevel { get; set; } public bool IsDeleted { get; set; } + + public string GetMessage() + { + //temporary fix until HTML parsing will be implemented + return MessageHTML.Remove(MessageHTML.LastIndexOf("

")).Substring(65); + } } } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index b22fefb3de..1b4bbee6a1 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Text = comment.MessageHTML, + Text = comment.GetMessage(), }, new Container { From 801b5b474e300343bafc0defc0a8818e3516919d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 13:45:13 +0300 Subject: [PATCH 291/966] Add a User property to the comment for easy access --- .../API/Requests/Responses/APIComments.cs | 20 ++++++++++++++++- .../Online/API/Requests/Responses/Comment.cs | 3 +++ osu.Game/Overlays/CommentsContainer.cs | 22 +++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index af7650e512..86bbf0358a 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -24,8 +24,26 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"included_comments")] public List IncludedComments { get; set; } + private List users; + [JsonProperty(@"users")] - public List Users { get; set; } + public List Users + { + get => users; + set + { + users = value; + + value.ForEach(u => + { + Comments.ForEach(c => + { + if (c.UserId == u.Id) + c.User = u; + }); + }); + } + } [JsonProperty(@"total")] public int Total { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index ba71faa843..46212dd50f 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using Newtonsoft.Json; +using osu.Game.Users; using System; namespace osu.Game.Online.API.Requests.Responses @@ -27,6 +28,8 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"user_id")] public long UserId { get; set; } + public User User { get; set; } + [JsonProperty(@"message")] public string Message { get; set; } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index 1b4bbee6a1..c871810d8a 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -103,11 +103,29 @@ namespace osu.Game.Overlays Height = 70, Children = new Drawable[] { - new SpriteText + new FillFlowContainer { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Text = comment.GetMessage(), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 3), + Children = new[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = $"user: {comment.User.Username}", + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = $"message: {comment.GetMessage()}", + }, + } }, new Container { From 1c89841949e025fe693aab73a97dd9a93c78b85b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 14:51:12 +0300 Subject: [PATCH 292/966] Move all the logic to it's own namespace --- .../Online/TestSceneCommentsContainer.cs | 2 +- .../{ => Comments}/CommentsContainer.cs | 67 +++---------- osu.Game/Overlays/Comments/DrawableComment.cs | 99 +++++++++++++++++++ 3 files changed, 116 insertions(+), 52 deletions(-) rename osu.Game/Overlays/{ => Comments}/CommentsContainer.cs (73%) create mode 100644 osu.Game/Overlays/Comments/DrawableComment.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index bf4117189a..e6f9582910 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using osu.Game.Overlays; using osu.Game.Online.API.Requests; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; +using osu.Game.Overlays.Comments; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs similarity index 73% rename from osu.Game/Overlays/CommentsContainer.cs rename to osu.Game/Overlays/Comments/CommentsContainer.cs index c871810d8a..60b22428f0 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.Sprites; using osuTK; using osu.Game.Online.API.Requests.Responses; -namespace osu.Game.Overlays +namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { @@ -90,59 +90,24 @@ namespace osu.Game.Overlays foreach (var c in response.Comments) { - if (!c.IsDeleted) - createDrawableComment(c); + if (!c.IsDeleted && c.IsTopLevel) + content.AddRange(new Drawable[] + { + new DrawableComment(c), + new Container + { + RelativeSizeAxes = Axes.X, + Height = 1, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray1, + } + } + }); } } - private void createDrawableComment(Comment comment) - { - content.Add(new Container - { - RelativeSizeAxes = Axes.X, - Height = 70, - Children = new Drawable[] - { - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 3), - Children = new[] - { - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = $"user: {comment.User.Username}", - }, - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = $"message: {comment.GetMessage()}", - }, - } - }, - new Container - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.X, - Height = 1, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - } - } - } - }); - } - [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs new file mode 100644 index 0000000000..bbb804dc5b --- /dev/null +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -0,0 +1,99 @@ +// 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.Containers; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users.Drawables; +using osu.Game.Graphics.Containers; +using osu.Game.Utils; + +namespace osu.Game.Overlays.Comments +{ + public class DrawableComment : CompositeDrawable + { + private const int avatar_size = 40; + private const int margin = 10; + + public DrawableComment(Comment comment) + { + LinkFlowContainer username; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding(margin), + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + new UpdateableAvatar(comment.User) + { + Size = new Vector2(avatar_size), + Margin = new MarginPadding { Horizontal = margin }, + Masking = true, + CornerRadius = avatar_size / 2, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Spacing = new Vector2(0, 2), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + }, + new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 18)) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = comment.GetMessage() + } + } + } + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) + } + } + } + }; + + username.AddUserLink(comment.User); + } + } +} From 2564214a72b70007368fa3c5763c407fab2192ac Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 15:01:18 +0300 Subject: [PATCH 293/966] Fix some padding issues with the big comments --- osu.Game/Overlays/Comments/DrawableComment.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index bbb804dc5b..6f3d92c7fd 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -54,21 +54,16 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Top = margin / 2 }, Spacing = new Vector2(0, 2), Children = new Drawable[] { username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, }, - new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 18)) + new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Text = comment.GetMessage() From 451a7342ce7459ae42562521e549af8e7e8a1d5b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 15:39:03 +0300 Subject: [PATCH 294/966] Parse child comments --- .../API/Requests/Responses/APIComments.cs | 22 +++- .../Online/API/Requests/Responses/Comment.cs | 3 + .../Overlays/Comments/CommentsContainer.cs | 4 +- osu.Game/Overlays/Comments/DrawableComment.cs | 106 +++++++++++------- 4 files changed, 92 insertions(+), 43 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index 86bbf0358a..9a12fb613e 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -9,8 +9,28 @@ namespace osu.Game.Online.API.Requests.Responses { public class APIComments { + private List comments; + [JsonProperty(@"comments")] - public List Comments { get; set; } + public List Comments + { + get => comments; + set + { + comments = value; + comments.ForEach(child => + { + if (child.ParentId != null) + { + comments.ForEach(parent => + { + if (parent.Id == child.ParentId) + parent.ChildComments.Add(child); + }); + } + }); + } + } [JsonProperty(@"has_more")] public bool HasMore { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 46212dd50f..cdc3c3204b 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using osu.Game.Users; using System; +using System.Collections.Generic; namespace osu.Game.Online.API.Requests.Responses { @@ -25,6 +26,8 @@ namespace osu.Game.Online.API.Requests.Responses } } + public List ChildComments = new List(); + [JsonProperty(@"user_id")] public long UserId { get; set; } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 60b22428f0..d02e74a5a4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -17,6 +17,8 @@ namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { + private const float separator_height = 1.5f; + private readonly CommentableType type; private readonly long id; @@ -97,7 +99,7 @@ namespace osu.Game.Overlays.Comments new Container { RelativeSizeAxes = Axes.X, - Height = 1, + Height = separator_height, Child = new Box { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 6f3d92c7fd..53366be878 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -17,78 +17,102 @@ namespace osu.Game.Overlays.Comments { private const int avatar_size = 40; private const int margin = 10; + private const int child_margin = 20; public DrawableComment(Comment comment) { LinkFlowContainer username; + FillFlowContainer childCommentsContainer; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - InternalChild = new GridContainer + InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Margin = new MarginPadding(margin), - ColumnDimensions = new[] + Direction = FillDirection.Vertical, + Children = new Drawable[] { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] + new GridContainer { - new UpdateableAvatar(comment.User) + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding(margin), + ColumnDimensions = new[] { - Size = new Vector2(avatar_size), - Margin = new MarginPadding { Horizontal = margin }, - Masking = true, - CornerRadius = avatar_size / 2, + new Dimension(GridSizeMode.AutoSize), + new Dimension(), }, - new FillFlowContainer + RowDimensions = new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = margin / 2 }, - Spacing = new Vector2(0, 2), - Children = new Drawable[] + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + new UpdateableAvatar(comment.User) { - AutoSizeAxes = Axes.Both, + Size = new Vector2(avatar_size), + Margin = new MarginPadding { Horizontal = margin }, + Masking = true, + CornerRadius = avatar_size / 2, }, - new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = comment.GetMessage() + Margin = new MarginPadding { Top = margin / 2 }, + Spacing = new Vector2(0, 2), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = comment.GetMessage() + } + } + } + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) } } } }, - new Drawable[] + childCommentsContainer = new FillFlowContainer { - new Container - { - RelativeSizeAxes = Axes.Both, - }, - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) - } + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical } } }; username.AddUserLink(comment.User); + + comment.ChildComments.ForEach(c => + { + if (!c.IsDeleted) + childCommentsContainer.Add(new DrawableComment(c)); + }); } } } From 9c7e403cf8ca62b83ded5505c030b77f8ee0a81b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 16:00:34 +0300 Subject: [PATCH 295/966] Implement replies button --- osu.Game/Overlays/Comments/DrawableComment.cs | 98 +++++++++++++++++-- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 53366be878..9879995b00 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -10,6 +10,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Utils; +using osu.Framework.Input.Events; +using System; namespace osu.Game.Overlays.Comments { @@ -18,11 +20,39 @@ namespace osu.Game.Overlays.Comments private const int avatar_size = 40; private const int margin = 10; private const int child_margin = 20; + private const int duration = 200; + + private bool childExpanded = true; + + public bool ChildExpanded + { + get => childExpanded; + set + { + if (childExpanded == value) + return; + + childExpanded = value; + + childCommentsVisibilityContainer.ClearTransforms(); + + if (childExpanded) + childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; + else + { + childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; + childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); + } + } + } + + private readonly Container childCommentsVisibilityContainer; public DrawableComment(Comment comment) { LinkFlowContainer username; FillFlowContainer childCommentsContainer; + RepliesButton replies; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -86,22 +116,40 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.Both, }, - new SpriteText + new FillFlowContainer { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) + }, + replies = new RepliesButton(comment.RepliesCount), + } } } } }, - childCommentsContainer = new FillFlowContainer + childCommentsVisibilityContainer = new Container { - Margin = new MarginPadding { Left = child_margin }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical + AutoSizeDuration = duration, + AutoSizeEasing = Easing.OutQuint, + Masking = true, + Child = childCommentsContainer = new FillFlowContainer + { + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + } } } }; @@ -113,6 +161,40 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted) childCommentsContainer.Add(new DrawableComment(c)); }); + + replies.Action += expanded => ChildExpanded = expanded; + } + + private class RepliesButton : Container + { + private readonly SpriteText text; + private bool expanded; + private readonly int count; + + public Action Action; + + public RepliesButton(int count) + { + this.count = count; + + AutoSizeAxes = Axes.Both; + Alpha = count == 0 ? 0 : 1; + Child = text = new SpriteText + { + Font = OsuFont.GetFont(size: 12), + Text = $@"[-] replies ({count})" + }; + + expanded = true; + } + + protected override bool OnClick(ClickEvent e) + { + text.Text = $@"{(expanded ? "[+]" : "[-]")} replies ({count})"; + expanded = !expanded; + Action?.Invoke(expanded); + return base.OnClick(e); + } } } } From 3f8fecbc5034d2b601ea6e6bc3643e25b8e13fc6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 16:04:52 +0300 Subject: [PATCH 296/966] Adjust spacing --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 9879995b00..f3d8d2f577 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.Comments { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), + Spacing = new Vector2(10, 0), Children = new Drawable[] { new SpriteText From 000e4a563cf4389d9fc86683838ece2e8251230b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:09:02 +0300 Subject: [PATCH 297/966] Parse parent comments --- .../API/Requests/Responses/APIComments.cs | 3 ++ .../Online/API/Requests/Responses/Comment.cs | 2 + osu.Game/Overlays/Comments/DrawableComment.cs | 45 ++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index 9a12fb613e..f454d4052f 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -25,7 +25,10 @@ namespace osu.Game.Online.API.Requests.Responses comments.ForEach(parent => { if (parent.Id == child.ParentId) + { parent.ChildComments.Add(child); + child.ParentComment = parent; + } }); } }); diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index cdc3c3204b..e5d3f14d27 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -28,6 +28,8 @@ namespace osu.Game.Online.API.Requests.Responses public List ChildComments = new List(); + public Comment ParentComment { get; set; } + [JsonProperty(@"user_id")] public long UserId { get; set; } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index f3d8d2f577..dea14f22c8 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Utils; using osu.Framework.Input.Events; using System; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Comments { @@ -97,9 +98,19 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(0, 2), Children = new Drawable[] { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + new FillFlowContainer { AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new ParentUsername(comment) + } }, new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { @@ -196,5 +207,37 @@ namespace osu.Game.Overlays.Comments return base.OnClick(e); } } + + private class ParentUsername : FillFlowContainer, IHasTooltip + { + private const int spacing = 3; + + public string TooltipText => comment.ParentComment?.GetMessage() ?? ""; + + private readonly Comment comment; + + public ParentUsername(Comment comment) + { + this.comment = comment; + + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(spacing, 0); + Alpha = comment.ParentId == null ? 0 : 1; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Reply, + Size = new Vector2(14), + }, + new SpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = comment.ParentComment?.User?.Username + } + }; + } + } } } From 341702b91d084207316711e6f43e33afa3fadcc6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:18:46 +0300 Subject: [PATCH 298/966] Use Bindable for expansion logic --- osu.Game/Overlays/Comments/DrawableComment.cs | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index dea14f22c8..bf24cbb70d 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -11,8 +11,8 @@ using osu.Game.Users.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Utils; using osu.Framework.Input.Events; -using System; using osu.Framework.Graphics.Cursor; +using osu.Framework.Bindables; namespace osu.Game.Overlays.Comments { @@ -23,29 +23,7 @@ namespace osu.Game.Overlays.Comments private const int child_margin = 20; private const int duration = 200; - private bool childExpanded = true; - - public bool ChildExpanded - { - get => childExpanded; - set - { - if (childExpanded == value) - return; - - childExpanded = value; - - childCommentsVisibilityContainer.ClearTransforms(); - - if (childExpanded) - childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; - else - { - childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; - childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); - } - } - } + private readonly BindableBool childExpanded = new BindableBool(true); private readonly Container childCommentsVisibilityContainer; @@ -53,7 +31,6 @@ namespace osu.Game.Overlays.Comments { LinkFlowContainer username; FillFlowContainer childCommentsContainer; - RepliesButton replies; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -141,7 +118,8 @@ namespace osu.Game.Overlays.Comments Font = OsuFont.GetFont(size: 12), Text = HumanizerUtils.Humanize(comment.CreatedAt) }, - replies = new RepliesButton(comment.RepliesCount), + new RepliesButton(comment.RepliesCount) + { Expanded = { BindTarget = childExpanded } }, } } } @@ -172,17 +150,33 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted) childCommentsContainer.Add(new DrawableComment(c)); }); + } - replies.Action += expanded => ChildExpanded = expanded; + protected override void LoadComplete() + { + childExpanded.BindValueChanged(onChildExpandedChanged, true); + base.LoadComplete(); + } + + private void onChildExpandedChanged(ValueChangedEvent expanded) + { + childCommentsVisibilityContainer.ClearTransforms(); + + if (expanded.NewValue) + childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; + else + { + childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; + childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); + } } private class RepliesButton : Container { private readonly SpriteText text; - private bool expanded; private readonly int count; - public Action Action; + public readonly BindableBool Expanded = new BindableBool(true); public RepliesButton(int count) { @@ -193,17 +187,23 @@ namespace osu.Game.Overlays.Comments Child = text = new SpriteText { Font = OsuFont.GetFont(size: 12), - Text = $@"[-] replies ({count})" }; + } - expanded = true; + protected override void LoadComplete() + { + Expanded.BindValueChanged(onExpandedChanged, true); + base.LoadComplete(); + } + + private void onExpandedChanged(ValueChangedEvent expanded) + { + text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})"; } protected override bool OnClick(ClickEvent e) { - text.Text = $@"{(expanded ? "[+]" : "[-]")} replies ({count})"; - expanded = !expanded; - Action?.Invoke(expanded); + Expanded.Value = !Expanded.Value; return base.OnClick(e); } } From 4230b00110768023bd1cf9d0e1fc098d5b273224 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:22:23 +0300 Subject: [PATCH 299/966] Rename APIComments to APICommentsController --- osu.Game/Online/API/Requests/GetCommentsRequest.cs | 2 +- .../Responses/{APIComments.cs => APICommentsController.cs} | 2 +- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename osu.Game/Online/API/Requests/Responses/{APIComments.cs => APICommentsController.cs} (98%) diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs index 279a1905da..5a2b61b4d0 100644 --- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -7,7 +7,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetCommentsRequest : APIRequest + public class GetCommentsRequest : APIRequest { private readonly long id; private readonly int page; diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs similarity index 98% rename from osu.Game/Online/API/Requests/Responses/APIComments.cs rename to osu.Game/Online/API/Requests/Responses/APICommentsController.cs index f454d4052f..cf2e5e8a35 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; namespace osu.Game.Online.API.Requests.Responses { - public class APIComments + public class APICommentsController { private List comments; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index d02e74a5a4..abbd2cdbde 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -86,7 +86,7 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } - private void onSuccess(APIComments response) + private void onSuccess(APICommentsController response) { content.Clear(); From 35cfb16c8d21594237251fbf63d4fd69491efc3f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:56:43 +0300 Subject: [PATCH 300/966] Implement VotePill component --- osu.Game/Overlays/Comments/DrawableComment.cs | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index bf24cbb70d..ce60d905ad 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -13,6 +13,8 @@ using osu.Game.Utils; using osu.Framework.Input.Events; using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; namespace osu.Game.Overlays.Comments { @@ -60,12 +62,28 @@ namespace osu.Game.Overlays.Comments { new Drawable[] { - new UpdateableAvatar(comment.User) + new FillFlowContainer { - Size = new Vector2(avatar_size), + AutoSizeAxes = Axes.Both, Margin = new MarginPadding { Horizontal = margin }, - Masking = true, - CornerRadius = avatar_size / 2, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + new VotePill(comment.VotesCount) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new UpdateableAvatar(comment.User) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = avatar_size / 2, + }, + } }, new FillFlowContainer { @@ -239,5 +257,34 @@ namespace osu.Game.Overlays.Comments }; } } + + private class VotePill : CircularContainer + { + private const int height = 20; + private const int margin = 10; + + public VotePill(int count) + { + AutoSizeAxes = Axes.X; + Height = height; + Masking = true; + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + new SpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = margin }, + Font = OsuFont.GetFont(size: 14), + Text = $"+{count}" + } + }; + } + } } } From b6047e46135cd099a1d21ebcd492d38cac7f5a3b Mon Sep 17 00:00:00 2001 From: HoLLy-HaCKeR Date: Tue, 8 Oct 2019 19:39:54 +0200 Subject: [PATCH 301/966] Move OsuCursor resize logic to OsuCursorContainer --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 36 ++----------------- .../UI/Cursor/OsuCursorContainer.cs | 34 ++++++++++++++++-- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index 41a02deaca..0aa8661fd3 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -2,14 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Skinning; using osu.Game.Skinning; using osuTK; @@ -23,12 +20,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private bool cursorExpand; - private Bindable cursorScale; - private Bindable autoCursorScale; - private readonly IBindable beatmap = new Bindable(); - private Container expandTarget; - private Drawable scaleTarget; public OsuCursor() { @@ -43,43 +35,19 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, IBindable beatmap) + private void load() { InternalChild = expandTarget = new Container { RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = scaleTarget = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) + Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) { Origin = Anchor.Centre, Anchor = Anchor.Centre, } }; - - this.beatmap.BindTo(beatmap); - this.beatmap.ValueChanged += _ => calculateScale(); - - cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); - cursorScale.ValueChanged += _ => calculateScale(); - - autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); - autoCursorScale.ValueChanged += _ => calculateScale(); - - calculateScale(); - } - - private void calculateScale() - { - float scale = cursorScale.Value; - - if (autoCursorScale.Value && beatmap.Value != null) - { - // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. - scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; - } - - scaleTarget.Scale = new Vector2(scale); } private const float pressed_scale = 1.2f; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 6dbdf0114d..e24ab3a7cb 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -8,6 +8,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; +using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.UI; using osu.Game.Skinning; @@ -27,6 +29,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Drawable cursorTrail; + private Bindable cursorScale; + private Bindable autoCursorScale; + private readonly IBindable beatmap = new Bindable(); + public OsuCursorContainer() { InternalChild = fadeContainer = new Container @@ -37,9 +43,33 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor } [BackgroundDependencyLoader(true)] - private void load(OsuRulesetConfigManager config) + private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig, IBindable beatmap) { - config?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail); + rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail); + + this.beatmap.BindTo(beatmap); + this.beatmap.ValueChanged += _ => calculateScale(); + + cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); + cursorScale.ValueChanged += _ => calculateScale(); + + autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); + autoCursorScale.ValueChanged += _ => calculateScale(); + + calculateScale(); + } + + private void calculateScale() + { + float scale = cursorScale.Value; + + if (autoCursorScale.Value && beatmap.Value != null) + { + // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. + scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; + } + + ActiveCursor.Scale = new Vector2(scale); } protected override void LoadComplete() From 1c22fb485fa2cc8b75f230c5a5ddcd40fa090534 Mon Sep 17 00:00:00 2001 From: HoLLy-HaCKeR Date: Tue, 8 Oct 2019 19:40:46 +0200 Subject: [PATCH 302/966] Scale cursortrail along with cursor --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index e24ab3a7cb..371c2983fc 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; } - ActiveCursor.Scale = new Vector2(scale); + ActiveCursor.Scale = cursorTrail.Scale = new Vector2(scale); } protected override void LoadComplete() From 9ab309fc0ef387e2226991c7f010e75f52fe1a19 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 20:44:01 +0300 Subject: [PATCH 303/966] Use bold font for replies button --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index ce60d905ad..ce78dfec9f 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -204,7 +204,7 @@ namespace osu.Game.Overlays.Comments Alpha = count == 0 ? 0 : 1; Child = text = new SpriteText { - Font = OsuFont.GetFont(size: 12), + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), }; } From b9ad079bf8b077ae7a9aa53bdb2da1e6dcc0993e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 20:57:55 +0300 Subject: [PATCH 304/966] Move CommentsHeader to it's own file --- .../Online/TestSceneCommentsContainer.cs | 2 + .../Overlays/Comments/CommentsContainer.cs | 56 --------------- osu.Game/Overlays/Comments/CommentsHeader.cs | 69 +++++++++++++++++++ 3 files changed, 71 insertions(+), 56 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CommentsHeader.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index e6f9582910..c8d16bdf21 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -17,6 +17,8 @@ namespace osu.Game.Tests.Visual.Online public override IReadOnlyList RequiredTypes => new[] { typeof(CommentsContainer), + typeof(CommentsHeader), + typeof(DrawableComment), }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index abbd2cdbde..f8783952d1 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -9,8 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Framework.Graphics.Sprites; -using osuTK; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Comments @@ -115,59 +113,5 @@ namespace osu.Game.Overlays.Comments { background.Colour = colours.Gray3; } - - private class CommentsHeader : CompositeDrawable - { - private const int height = 40; - private const int spacing = 10; - private const int padding = 50; - - public readonly Bindable Sort = new Bindable(); - - private readonly Box background; - - public CommentsHeader() - { - RelativeSizeAxes = Axes.X; - Height = height; - AddRangeInternal(new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = padding }, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(spacing, 0), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - new SpriteText - { - Font = OsuFont.GetFont(size: 14), - Text = @"Sort by" - } - } - } - } - } - }); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - background.Colour = colours.Gray4; - } - } } } diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs new file mode 100644 index 0000000000..9ebd257a5d --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -0,0 +1,69 @@ +// 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.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests; +using osu.Framework.Graphics; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public class CommentsHeader : CompositeDrawable + { + private const int height = 40; + private const int spacing = 10; + private const int padding = 50; + + public readonly Bindable Sort = new Bindable(); + + private readonly Box background; + + public CommentsHeader() + { + RelativeSizeAxes = Axes.X; + Height = height; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = padding }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new SpriteText + { + Font = OsuFont.GetFont(size: 14), + Text = @"Sort by" + } + } + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray4; + } + } +} From 574170124cff05070833415e324f77a2e5fe88ef Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 21:38:19 +0300 Subject: [PATCH 305/966] Implement HeaderButton component --- .../Online/TestSceneCommentsContainer.cs | 1 + osu.Game/Overlays/Comments/CommentsHeader.cs | 63 ++++++++++++++++- osu.Game/Overlays/Comments/HeaderButton.cs | 68 +++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Comments/HeaderButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index c8d16bdf21..f5205552e0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -19,6 +19,7 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsContainer), typeof(CommentsHeader), typeof(DrawableComment), + typeof(HeaderButton), }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index 9ebd257a5d..b9dee7935e 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; +using osu.Framework.Input.Events; namespace osu.Game.Overlays.Comments { @@ -18,8 +19,10 @@ namespace osu.Game.Overlays.Comments private const int height = 40; private const int spacing = 10; private const int padding = 50; + private const int text_size = 14; public readonly Bindable Sort = new Bindable(); + public readonly BindableBool ShowDeleted = new BindableBool(); private readonly Box background; @@ -50,10 +53,16 @@ namespace osu.Game.Overlays.Comments { new SpriteText { - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(size: text_size), Text = @"Sort by" } } + }, + new ShowDeletedButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Checked = { BindTarget = ShowDeleted } } } } @@ -65,5 +74,57 @@ namespace osu.Game.Overlays.Comments { background.Colour = colours.Gray4; } + + private class ShowDeletedButton : HeaderButton + { + private const int spacing = 5; + + public readonly BindableBool Checked = new BindableBool(); + + private readonly SpriteIcon checkboxIcon; + + public ShowDeletedButton() + { + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Children = new Drawable[] + { + checkboxIcon = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(10), + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: text_size), + Text = @"Show deleted" + } + }, + }); + } + + protected override void LoadComplete() + { + Checked.BindValueChanged(onCheckedChanged, true); + base.LoadComplete(); + } + + private void onCheckedChanged(ValueChangedEvent isChecked) + { + checkboxIcon.Icon = isChecked.NewValue ? FontAwesome.Solid.CheckSquare : FontAwesome.Regular.Square; + } + + protected override bool OnClick(ClickEvent e) + { + Checked.Value = !Checked.Value; + return base.OnClick(e); + } + } } } diff --git a/osu.Game/Overlays/Comments/HeaderButton.cs b/osu.Game/Overlays/Comments/HeaderButton.cs new file mode 100644 index 0000000000..db8ea92a1a --- /dev/null +++ b/osu.Game/Overlays/Comments/HeaderButton.cs @@ -0,0 +1,68 @@ +// 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.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Comments +{ + public class HeaderButton : Container + { + private const int height = 20; + private const int corner_radius = 3; + private const int margin = 10; + private const int duration = 200; + + protected override Container Content => content; + + private readonly Box background; + private readonly Container content; + + public HeaderButton() + { + AutoSizeAxes = Axes.X; + Height = height; + Masking = true; + CornerRadius = corner_radius; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + content = new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = margin } + }, + new HoverClickSounds(), + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray6; + } + + protected override bool OnHover(HoverEvent e) + { + background.FadeIn(duration, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + background.FadeOut(duration, Easing.OutQuint); + } + } +} From 29b0eacc821b5091c0251d6066e2e52296d8c279 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 22:46:42 +0300 Subject: [PATCH 306/966] Implement SortSelector component --- .../Online/TestSceneCommentsContainer.cs | 1 + .../Online/API/Requests/GetCommentsRequest.cs | 2 +- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 3 +- osu.Game/Overlays/Comments/CommentsHeader.cs | 8 ++ osu.Game/Overlays/Comments/DrawableComment.cs | 9 ++- osu.Game/Overlays/Comments/HeaderButton.cs | 8 +- osu.Game/Overlays/Comments/SortSelector.cs | 75 +++++++++++++++++++ 8 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Overlays/Comments/SortSelector.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index f5205552e0..7fbe9d7e8b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -20,6 +20,7 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsHeader), typeof(DrawableComment), typeof(HeaderButton), + typeof(SortSelector) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs index 5a2b61b4d0..02a36f7aa2 100644 --- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Online.API.Requests req.AddParameter("commentable_type", type.ToString().Underscore().ToLowerInvariant()); req.AddParameter("commentable_id", id.ToString()); - req.AddParameter("sort", sort.ToString()); + req.AddParameter("sort", sort.ToString().ToLowerInvariant()); req.AddParameter("page", page.ToString()); return req; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e5d3f14d27..30aca3c2ea 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -31,7 +31,7 @@ namespace osu.Game.Online.API.Requests.Responses public Comment ParentComment { get; set; } [JsonProperty(@"user_id")] - public long UserId { get; set; } + public long? UserId { get; set; } public User User { get; set; } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index f8783952d1..5be1b6c1c4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -79,6 +79,7 @@ namespace osu.Game.Overlays.Comments private void getComments() { request?.Cancel(); + content.Clear(); request = new GetCommentsRequest(type, id, Sort.Value); request.Success += onSuccess; api.Queue(request); @@ -86,8 +87,6 @@ namespace osu.Game.Overlays.Comments private void onSuccess(APICommentsController response) { - content.Clear(); - foreach (var c in response.Comments) { if (!c.IsDeleted && c.IsTopLevel) diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index b9dee7935e..90a6f44d6b 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -53,8 +53,16 @@ namespace osu.Game.Overlays.Comments { new SpriteText { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: text_size), Text = @"Sort by" + }, + new SortSelector + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = { BindTarget = Sort } } } }, diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index ce78dfec9f..41b30513a1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -161,7 +161,14 @@ namespace osu.Game.Overlays.Comments } }; - username.AddUserLink(comment.User); + if (comment.UserId == null) + { + username.AddText(comment.LegacyName); + } + else + { + username.AddUserLink(comment.User); + } comment.ChildComments.ForEach(c => { diff --git a/osu.Game/Overlays/Comments/HeaderButton.cs b/osu.Game/Overlays/Comments/HeaderButton.cs index db8ea92a1a..e3729b3b05 100644 --- a/osu.Game/Overlays/Comments/HeaderButton.cs +++ b/osu.Game/Overlays/Comments/HeaderButton.cs @@ -55,14 +55,18 @@ namespace osu.Game.Overlays.Comments protected override bool OnHover(HoverEvent e) { - background.FadeIn(duration, Easing.OutQuint); + FadeInBackground(); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); - background.FadeOut(duration, Easing.OutQuint); + FadeOutBackground(); } + + public void FadeInBackground() => background.FadeIn(duration, Easing.OutQuint); + + public void FadeOutBackground() => background.FadeOut(duration, Easing.OutQuint); } } diff --git a/osu.Game/Overlays/Comments/SortSelector.cs b/osu.Game/Overlays/Comments/SortSelector.cs new file mode 100644 index 0000000000..4425145c3e --- /dev/null +++ b/osu.Game/Overlays/Comments/SortSelector.cs @@ -0,0 +1,75 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API.Requests; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osuTK; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Comments +{ + public class SortSelector : OsuTabControl + { + private const int spacing = 5; + + protected override Dropdown CreateDropdown() => null; + + protected override TabItem CreateTabItem(SortCommentsBy value) => new SortTabItem(value); + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + }; + + public SortSelector() + { + AutoSizeAxes = Axes.Both; + } + + private class SortTabItem : TabItem + { + private readonly TabContent content; + + public SortTabItem(SortCommentsBy value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Child = content = new TabContent(value) + { Active = { BindTarget = Active } }; + } + + protected override void OnActivated() => content.FadeInBackground(); + + protected override void OnDeactivated() => content.FadeOutBackground(); + + private class TabContent : HeaderButton + { + private const int text_size = 14; + + public readonly BindableBool Active = new BindableBool(); + + public TabContent(SortCommentsBy value) + { + Add(new SpriteText + { + Font = OsuFont.GetFont(size: text_size), + Text = value.ToString() + }); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + if (!Active.Value) base.OnHoverLost(e); + } + } + } + } +} From 3dd2b18ff0d32cb717bddd6c982e42ca3a7a723f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:04:58 +0900 Subject: [PATCH 307/966] Make EditorScreen abstract --- osu.Game/Screens/Edit/Editor.cs | 6 +----- osu.Game/Screens/Edit/EditorScreen.cs | 15 +++++---------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 9ebe3bc26a..7f08c2f8b9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -19,13 +19,13 @@ using osu.Framework.Timing; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components.Menus; -using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Design; using osuTK.Input; using System.Collections.Generic; using osu.Framework; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; +using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Edit.Timing; using osu.Game.Users; @@ -275,10 +275,6 @@ namespace osu.Game.Screens.Edit case EditorScreenMode.Timing: currentScreen = new TimingScreen(); break; - - default: - currentScreen = new EditorScreen(); - break; } LoadComponentAsync(currentScreen, screenContainer.Add); diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index 045e5a1226..1b57c703ae 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -10,16 +10,17 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Edit { /// - /// TODO: eventually make this inherit Screen and add a local scren stack inside the Editor. + /// TODO: eventually make this inherit Screen and add a local screen stack inside the Editor. /// - public class EditorScreen : Container + public abstract class EditorScreen : Container { - protected readonly IBindable Beatmap = new Bindable(); + [Resolved] + protected IBindable Beatmap { get; private set; } protected override Container Content => content; private readonly Container content; - public EditorScreen() + protected EditorScreen() { Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -28,12 +29,6 @@ namespace osu.Game.Screens.Edit InternalChild = content = new Container { RelativeSizeAxes = Axes.Both }; } - [BackgroundDependencyLoader] - private void load(IBindable beatmap) - { - Beatmap.BindTo(beatmap); - } - protected override void LoadComplete() { base.LoadComplete(); From f2adae8fd167195b667989d30d7bc99b09e12ba3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:05:38 +0900 Subject: [PATCH 308/966] Rename test case to better match underlying class --- ...{TestSceneEditorCompose.cs => TestSceneComposeScreen.cs} | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) rename osu.Game.Tests/Visual/Editor/{TestSceneEditorCompose.cs => TestSceneComposeScreen.cs} (72%) diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs similarity index 72% rename from osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs rename to osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs index 608df1965e..9f16e1d781 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs @@ -1,8 +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 System; -using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Rulesets.Osu; @@ -11,10 +9,8 @@ using osu.Game.Screens.Edit.Compose; namespace osu.Game.Tests.Visual.Editor { [TestFixture] - public class TestSceneEditorCompose : EditorClockTestScene + public class TestSceneComposeScreen : EditorClockTestScene { - public override IReadOnlyList RequiredTypes => new[] { typeof(ComposeScreen) }; - [BackgroundDependencyLoader] private void load() { From 2d8e5615e4970fc1f47a94ed2690d6f2c0cb8a99 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:05:55 +0900 Subject: [PATCH 309/966] Extract timeline and layout logic from ComposeScreen --- .../Screens/Edit/Compose/ComposeScreen.cs | 111 +----------------- .../Screens/Edit/EditorScreenWithTimeline.cs | 107 +++++++++++++++++ 2 files changed, 112 insertions(+), 106 deletions(-) create mode 100644 osu.Game/Screens/Edit/EditorScreenWithTimeline.cs diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 2a99d81516..1d93c6d4a4 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -1,112 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Logging; -using osu.Game.Screens.Edit.Compose.Components; -using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Skinning; -using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose { - public class ComposeScreen : EditorScreen + public class ComposeScreen : EditorScreenWithTimeline { - private const float vertical_margins = 10; - private const float horizontal_margins = 20; - - private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - - [BackgroundDependencyLoader(true)] - private void load([CanBeNull] BindableBeatDivisor beatDivisor) + protected override Drawable CreateMainContent() { - if (beatDivisor != null) - this.beatDivisor.BindTo(beatDivisor); - - Container composerContainer; - - Children = new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - Name = "Timeline", - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.5f) - }, - new Container - { - Name = "Timeline content", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 5 }, - Child = new TimelineArea { RelativeSizeAxes = Axes.Both } - }, - new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both } - }, - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 90), - } - }, - } - } - } - }, - new Drawable[] - { - composerContainer = new Container - { - Name = "Composer content", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, - } - } - }, - RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 110) } - }, - }; - var ruleset = Beatmap.Value.BeatmapInfo.Ruleset?.CreateInstance(); - if (ruleset == null) - { - Logger.Log("Beatmap doesn't have a ruleset assigned."); - // ExitRequested?.Invoke(); - return; - } - - var composer = ruleset.CreateHitObjectComposer(); - - Drawable content; + var composer = ruleset?.CreateHitObjectComposer(); if (composer != null) { @@ -118,18 +25,10 @@ namespace osu.Game.Screens.Edit.Compose // load the skinning hierarchy first. // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. - content = beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); - } - else - { - content = new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); + return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); } - LoadComponentAsync(content, _ => - { - composerContainer.Add(content); - content.FadeInFromZero(300, Easing.OutQuint); - }); + return new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); } } } diff --git a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs new file mode 100644 index 0000000000..752356e8c4 --- /dev/null +++ b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs @@ -0,0 +1,107 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit +{ + public abstract class EditorScreenWithTimeline : EditorScreen + { + private const float vertical_margins = 10; + private const float horizontal_margins = 20; + + private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); + + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] BindableBeatDivisor beatDivisor) + { + if (beatDivisor != null) + this.beatDivisor.BindTo(beatDivisor); + + Container mainContent; + + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + Name = "Timeline", + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.5f) + }, + new Container + { + Name = "Timeline content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 5 }, + Child = CreateTimeline() + }, + new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both } + }, + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 90), + } + }, + } + } + } + }, + new Drawable[] + { + mainContent = new Container + { + Name = "Main content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, + } + } + }, + RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 110) } + }, + }; + + LoadComponentAsync(CreateMainContent(), content => + { + mainContent.Add(content); + content.FadeInFromZero(300, Easing.OutQuint); + }); + } + + protected abstract Drawable CreateMainContent(); + + protected virtual Drawable CreateTimeline() => new TimelineArea { RelativeSizeAxes = Axes.Both }; + } +} From faef4d932d08cc7ef5fde89d88953b3c21cd7ac6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 10:17:14 +0300 Subject: [PATCH 310/966] Improve message parsing --- osu.Game/Online/API/Requests/Responses/Comment.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 30aca3c2ea..fb0aad0e0b 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -87,8 +87,7 @@ namespace osu.Game.Online.API.Requests.Responses public string GetMessage() { - //temporary fix until HTML parsing will be implemented - return MessageHTML.Remove(MessageHTML.LastIndexOf("

")).Substring(65); + return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", ""); } } } From 4462d454e87fba91a25b92b3bc4fef0a9ba6007c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 10:34:17 +0300 Subject: [PATCH 311/966] Message padding improvements --- osu.Game/Overlays/Comments/CommentsContainer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 5be1b6c1c4..b9effb39e8 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -16,6 +16,7 @@ namespace osu.Game.Overlays.Comments public class CommentsContainer : CompositeDrawable { private const float separator_height = 1.5f; + private const int padding = 40; private readonly CommentableType type; private readonly long id; @@ -92,7 +93,13 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted && c.IsTopLevel) content.AddRange(new Drawable[] { - new DrawableComment(c), + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Right = padding }, + Child = new DrawableComment(c) + }, new Container { RelativeSizeAxes = Axes.X, From 0681bb9a2b27f063ae0153ca204b25a895334db1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:49:10 +0900 Subject: [PATCH 312/966] Fix potential nullref --- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 1d93c6d4a4..2e9094ebe6 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Compose return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); } - return new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); + return new ScreenWhiteBox.UnderConstructionMessage(ruleset == null ? "This beatmap" : $"{ruleset.Description}'s composer"); } } } From 0a56b041fdf7116ceb72d8a7251383f912961f5f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 11:07:56 +0300 Subject: [PATCH 313/966] Implement ShowChildsButton --- .../Online/TestSceneCommentsContainer.cs | 3 +- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 9 +-- osu.Game/Overlays/Comments/DrawableComment.cs | 72 ++++++++++++------- .../Overlays/Comments/ShowChildsButton.cs | 34 +++++++++ 5 files changed, 85 insertions(+), 35 deletions(-) create mode 100644 osu.Game/Overlays/Comments/ShowChildsButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 7fbe9d7e8b..4187771963 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -20,7 +20,8 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsHeader), typeof(DrawableComment), typeof(HeaderButton), - typeof(SortSelector) + typeof(SortSelector), + typeof(ShowChildsButton) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index fb0aad0e0b..9a3dee30b4 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -87,7 +87,7 @@ namespace osu.Game.Online.API.Requests.Responses public string GetMessage() { - return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", ""); + return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); } } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index b9effb39e8..5be1b6c1c4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -16,7 +16,6 @@ namespace osu.Game.Overlays.Comments public class CommentsContainer : CompositeDrawable { private const float separator_height = 1.5f; - private const int padding = 40; private readonly CommentableType type; private readonly long id; @@ -93,13 +92,7 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted && c.IsTopLevel) content.AddRange(new Drawable[] { - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Right = padding }, - Child = new DrawableComment(c) - }, + new DrawableComment(c), new Container { RelativeSizeAxes = Axes.X, diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 41b30513a1..a66b8fcd44 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -10,11 +10,11 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Utils; -using osu.Framework.Input.Events; using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using osuTK.Graphics; +using System.Linq; namespace osu.Game.Overlays.Comments { @@ -23,6 +23,8 @@ namespace osu.Game.Overlays.Comments private const int avatar_size = 40; private const int margin = 10; private const int child_margin = 20; + private const int chevron_margin = 30; + private const int message_padding = 40; private const int duration = 200; private readonly BindableBool childExpanded = new BindableBool(true); @@ -93,25 +95,41 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(0, 2), Children = new Drawable[] { - new FillFlowContainer + new Container { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(7, 0), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Children = new Drawable[] { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + new FillFlowContainer { AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new ParentUsername(comment) + } }, - new ParentUsername(comment) + new ChevronButton(comment) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = chevron_margin }, + Expanded = { BindTarget = childExpanded } + } } }, new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = comment.GetMessage() + Text = comment.GetMessage(), + Padding = new MarginPadding { Right = message_padding } } } } @@ -196,18 +214,34 @@ namespace osu.Game.Overlays.Comments } } - private class RepliesButton : Container + private class ChevronButton : ShowChildsButton + { + private readonly SpriteIcon icon; + + public ChevronButton(Comment comment) + { + Alpha = comment.IsTopLevel && comment.ChildComments.Any() ? 1 : 0; + Child = icon = new SpriteIcon + { + Size = new Vector2(12), + }; + } + + protected override void OnExpandedChanged(ValueChangedEvent expanded) + { + icon.Icon = expanded.NewValue ? FontAwesome.Solid.ChevronUp : FontAwesome.Solid.ChevronDown; + } + } + + private class RepliesButton : ShowChildsButton { private readonly SpriteText text; private readonly int count; - public readonly BindableBool Expanded = new BindableBool(true); - public RepliesButton(int count) { this.count = count; - AutoSizeAxes = Axes.Both; Alpha = count == 0 ? 0 : 1; Child = text = new SpriteText { @@ -215,22 +249,10 @@ namespace osu.Game.Overlays.Comments }; } - protected override void LoadComplete() - { - Expanded.BindValueChanged(onExpandedChanged, true); - base.LoadComplete(); - } - - private void onExpandedChanged(ValueChangedEvent expanded) + protected override void OnExpandedChanged(ValueChangedEvent expanded) { text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})"; } - - protected override bool OnClick(ClickEvent e) - { - Expanded.Value = !Expanded.Value; - return base.OnClick(e); - } } private class ParentUsername : FillFlowContainer, IHasTooltip diff --git a/osu.Game/Overlays/Comments/ShowChildsButton.cs b/osu.Game/Overlays/Comments/ShowChildsButton.cs new file mode 100644 index 0000000000..81280a71b5 --- /dev/null +++ b/osu.Game/Overlays/Comments/ShowChildsButton.cs @@ -0,0 +1,34 @@ +// 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; +using osu.Game.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Comments +{ + public abstract class ShowChildsButton : OsuHoverContainer + { + public readonly BindableBool Expanded = new BindableBool(true); + + public ShowChildsButton() + { + AutoSizeAxes = Axes.Both; + } + + protected override void LoadComplete() + { + Expanded.BindValueChanged(OnExpandedChanged, true); + base.LoadComplete(); + } + + protected abstract void OnExpandedChanged(ValueChangedEvent expanded); + + protected override bool OnClick(ClickEvent e) + { + Expanded.Value = !Expanded.Value; + return base.OnClick(e); + } + } +} From a0dfbfe1488e9cbb66ad068828fdbf88069b24ec Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 11:18:26 +0300 Subject: [PATCH 314/966] Handle parent usernames for legacy comments --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index a66b8fcd44..6215f5e108 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -281,7 +281,7 @@ namespace osu.Game.Overlays.Comments new SpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = comment.ParentComment?.User?.Username + Text = comment.ParentComment?.User?.Username ?? comment.ParentComment?.LegacyName } }; } From ad99a3236f052d2f2130a8c3559093f5c3c3699d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 11:32:17 +0300 Subject: [PATCH 315/966] Handle edited comments --- .../Requests/Responses/APICommentsController.cs | 3 +++ osu.Game/Online/API/Requests/Responses/Comment.cs | 2 ++ osu.Game/Overlays/Comments/DrawableComment.cs | 14 +++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APICommentsController.cs b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs index cf2e5e8a35..ca6062e371 100644 --- a/osu.Game/Online/API/Requests/Responses/APICommentsController.cs +++ b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs @@ -63,6 +63,9 @@ namespace osu.Game.Online.API.Requests.Responses { if (c.UserId == u.Id) c.User = u; + + if (c.EditedById == u.Id) + c.EditedUser = u; }); }); } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 9a3dee30b4..e420a585fe 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -81,6 +81,8 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"edited_by_id")] public long? EditedById { get; set; } + public User EditedUser { get; set; } + public bool IsTopLevel { get; set; } public bool IsDeleted { get; set; } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 6215f5e108..92b59a985b 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -35,6 +35,7 @@ namespace osu.Game.Overlays.Comments { LinkFlowContainer username; FillFlowContainer childCommentsContainer; + FillFlowContainer info; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.Both, }, - new FillFlowContainer + info = new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, @@ -188,6 +189,17 @@ namespace osu.Game.Overlays.Comments username.AddUserLink(comment.User); } + if (comment.EditedAt.HasValue) + { + info.Add(new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = $@"edited {HumanizerUtils.Humanize(comment.EditedAt.Value)} by {comment.EditedUser.Username}" + }); + } + comment.ChildComments.ForEach(c => { if (!c.IsDeleted) From b2bd78308dc4473d89d89244b873e5bd97b9f54f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 12:18:49 +0300 Subject: [PATCH 316/966] Handle deleted comments --- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 24 +-- osu.Game/Overlays/Comments/DrawableComment.cs | 150 +++++++++++------- 3 files changed, 98 insertions(+), 78 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e420a585fe..76a322e5c9 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -89,7 +89,7 @@ namespace osu.Game.Online.API.Requests.Responses public string GetMessage() { - return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); + return IsDeleted ? @"deleted" : MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); } } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 5be1b6c1c4..fb97f08a6e 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -15,12 +15,11 @@ namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { - private const float separator_height = 1.5f; - private readonly CommentableType type; private readonly long id; public readonly Bindable Sort = new Bindable(); + public readonly BindableBool ShowDeleted = new BindableBool(); [Resolved] private IAPIProvider api { get; set; } @@ -55,7 +54,8 @@ namespace osu.Game.Overlays.Comments { new CommentsHeader { - Sort = { BindTarget = Sort } + Sort = { BindTarget = Sort }, + ShowDeleted = { BindTarget = ShowDeleted } }, content = new FillFlowContainer { @@ -89,21 +89,9 @@ namespace osu.Game.Overlays.Comments { foreach (var c in response.Comments) { - if (!c.IsDeleted && c.IsTopLevel) - content.AddRange(new Drawable[] - { - new DrawableComment(c), - new Container - { - RelativeSizeAxes = Axes.X, - Height = separator_height, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - } - } - }); + if (c.IsTopLevel) + content.Add(new DrawableComment(c) + { ShowDeleted = { BindTarget = ShowDeleted } }); } } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 92b59a985b..4092cbb177 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -26,19 +26,29 @@ namespace osu.Game.Overlays.Comments private const int chevron_margin = 30; private const int message_padding = 40; private const int duration = 200; + private const float separator_height = 1.5f; + + public readonly BindableBool ShowDeleted = new BindableBool(); private readonly BindableBool childExpanded = new BindableBool(true); private readonly Container childCommentsVisibilityContainer; + private readonly Comment comment; public DrawableComment(Comment comment) { LinkFlowContainer username; FillFlowContainer childCommentsContainer; FillFlowContainer info; + TextFlowContainer message; + GridContainer content; + VotePill votePill; + + this.comment = comment; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + Masking = true; InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -46,7 +56,7 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - new GridContainer + content = new GridContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -58,7 +68,6 @@ namespace osu.Game.Overlays.Comments }, RowDimensions = new[] { - new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.AutoSize) }, Content = new[] @@ -73,10 +82,11 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(5, 0), Children = new Drawable[] { - new VotePill(comment.VotesCount) + votePill = new VotePill(comment.VotesCount) { Anchor = Anchor.Centre, Origin = Anchor.Centre, + AlwaysPresent = true, }, new UpdateableAvatar(comment.User) { @@ -92,71 +102,53 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = margin / 2 }, - Spacing = new Vector2(0, 2), + Spacing = new Vector2(0, 3), Children = new Drawable[] { - new Container + new FillFlowContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), Children = new Drawable[] { - new FillFlowContainer + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) { AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(7, 0), - Children = new Drawable[] - { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) - { - AutoSizeAxes = Axes.Both, - }, - new ParentUsername(comment) - } }, - new ChevronButton(comment) + new ParentUsername(comment), + new SpriteText { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Margin = new MarginPadding { Right = chevron_margin }, - Expanded = { BindTarget = childExpanded } + Alpha = comment.IsDeleted? 1 : 0, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = @"deleted", } } }, - new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + message = new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = comment.GetMessage(), Padding = new MarginPadding { Right = message_padding } - } - } - } - }, - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - }, - info = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) }, - new RepliesButton(comment.RepliesCount) - { Expanded = { BindTarget = childExpanded } }, + info = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) + }, + new RepliesButton(comment.RepliesCount) + { Expanded = { BindTarget = childExpanded } }, + } + } } } } @@ -181,13 +173,9 @@ namespace osu.Game.Overlays.Comments }; if (comment.UserId == null) - { username.AddText(comment.LegacyName); - } else - { username.AddUserLink(comment.User); - } if (comment.EditedAt.HasValue) { @@ -200,15 +188,45 @@ namespace osu.Game.Overlays.Comments }); } - comment.ChildComments.ForEach(c => + if (!comment.IsDeleted) + message.Text = comment.GetMessage(); + else { - if (!c.IsDeleted) - childCommentsContainer.Add(new DrawableComment(c)); - }); + content.FadeColour(OsuColour.Gray(0.5f)); + votePill.Hide(); + } + + if (comment.IsTopLevel) + { + AddInternal(new Container + { + RelativeSizeAxes = Axes.X, + Height = separator_height, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.1f) + } + }); + + if (comment.ChildComments.Any()) + { + AddInternal(new ChevronButton(comment) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = chevron_margin, Top = margin }, + Expanded = { BindTarget = childExpanded } + }); + } + } + + comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c))); } protected override void LoadComplete() { + ShowDeleted.BindValueChanged(onShowDeletedChanged, true); childExpanded.BindValueChanged(onChildExpandedChanged, true); base.LoadComplete(); } @@ -226,6 +244,20 @@ namespace osu.Game.Overlays.Comments } } + private void onShowDeletedChanged(ValueChangedEvent show) + { + if (comment.IsDeleted) + { + if (show.NewValue) + AutoSizeAxes = Axes.Y; + else + { + AutoSizeAxes = Axes.None; + this.ResizeHeightTo(0); + } + } + } + private class ChevronButton : ShowChildsButton { private readonly SpriteIcon icon; From 93d2c3d7a1c43cb9871f1bcb779b51cddcc086e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:03:20 +0900 Subject: [PATCH 317/966] Warn on incorrect null usage --- osu.sln.DotSettings | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index ed162eed6e..ae08a1666f 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -17,7 +17,8 @@ WARNING WARNING HINT - HINT + + True HINT HINT WARNING @@ -738,6 +739,7 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True True True From 51bf600ea7a830d736a748342bd987e6cc4dc878 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:08:31 +0900 Subject: [PATCH 318/966] Use empty hitwindows instead of null --- .../Objects/CatchHitObject.cs | 2 +- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 +- .../Objects/HoldNoteTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- .../Objects/SliderTailCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 2 +- .../Objects/DrumRollTick.cs | 2 +- .../Objects/StrongHitObject.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/SwellTick.cs | 2 +- osu.Game/Rulesets/Objects/HitObject.cs | 6 +--- .../Objects/Legacy/Mania/ConvertHit.cs | 2 +- .../Objects/Legacy/Mania/ConvertHold.cs | 2 +- .../Objects/Legacy/Mania/ConvertSlider.cs | 2 +- .../Objects/Legacy/Mania/ConvertSpinner.cs | 2 +- .../Rulesets/Objects/Legacy/Osu/ConvertHit.cs | 2 +- .../Objects/Legacy/Osu/ConvertSlider.cs | 2 +- .../Objects/Legacy/Osu/ConvertSpinner.cs | 2 +- .../Objects/Legacy/Taiko/ConvertHit.cs | 2 +- .../Objects/Legacy/Taiko/ConvertSlider.cs | 2 +- .../Objects/Legacy/Taiko/ConvertSpinner.cs | 2 +- osu.Game/Rulesets/Scoring/HitWindows.cs | 35 +++++++++++++++++++ osu.Game/Rulesets/UI/DrawableRuleset.cs | 4 +-- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 2 +- 27 files changed, 62 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 77d7de989a..e4ad49ea50 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Objects Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } public enum FruitVisualRepresentation diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 0c82cf7bbc..bdba813eed 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -101,6 +101,6 @@ namespace osu.Game.Rulesets.Mania.Objects public override Judgement CreateJudgement() => new HoldNoteJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs index d0125f8793..ac6697a6dc 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Mania.Objects { public override Judgement CreateJudgement() => new HoldNoteTickJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs index a794e57c9e..a277517f9f 100644 --- a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs @@ -30,6 +30,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 3ed1f2cdde..9bed123465 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -205,6 +205,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index 7e540a577b..14c3369967 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -25,6 +25,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuSliderTailJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs index af7cf5b144..a49f4cef8b 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs @@ -32,6 +32,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 2e7b763966..2441a1449d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -33,6 +33,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 4e02c76a8b..8956ca9c19 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -88,6 +88,6 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index c466ca7c8a..8a8be3e38d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -27,6 +27,6 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs index d660149528..72a04698be 100644 --- a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs @@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public override Judgement CreateJudgement() => new TaikoStrongJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index f96c033dce..e60984596d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -35,6 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoSwellJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs index 68212e8f12..91f4d3dbe7 100644 --- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs @@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public override Judgement CreateJudgement() => new TaikoSwellTickJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index a99fac09cc..eb8652443f 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -66,7 +66,6 @@ namespace osu.Game.Rulesets.Objects /// /// The hit windows for this . /// - [CanBeNull] public HitWindows HitWindows { get; set; } private readonly List nestedHitObjects = new List(); @@ -113,10 +112,7 @@ namespace osu.Game.Rulesets.Objects nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); foreach (var h in nestedHitObjects) - { - h.HitWindows = HitWindows; h.ApplyDefaults(controlPointInfo, difficulty); - } } protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) @@ -147,7 +143,7 @@ namespace osu.Game.Rulesets.Objects /// This will only be invoked if hasn't been set externally (e.g. from a . /// ///
- [CanBeNull] + [NotNull] protected virtual HitWindows CreateHitWindows() => new HitWindows(); } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs index 609bdd571a..883ef55df0 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs @@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania { public float X { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs index 350ee3185d..69e6f8379d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania public double Duration => EndTime - StartTime; - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs index e372fbd273..4486c5d906 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs @@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania { public float X { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs index 067377d300..c6d1f1922c 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs @@ -17,6 +17,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania public float X { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs index c9851a0074..e40b5b4505 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs @@ -22,6 +22,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public int ComboOffset { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs index 1c1180702b..a163329d47 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs @@ -22,6 +22,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public int ComboOffset { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs index bc94ea1803..5d96a61633 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public float Y => Position.Y; - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; public bool NewCombo { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs index 709345170f..efb9810927 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs @@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// internal sealed class ConvertHit : HitObject { - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs index c173b3e11a..b365fd34ae 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs @@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// internal sealed class ConvertSlider : Legacy.ConvertSlider { - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs index 9a35ad2776..840ba51ac2 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko public double Duration => EndTime - StartTime; - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs index efc4cd9f5c..9e7e594104 100644 --- a/osu.Game/Rulesets/Scoring/HitWindows.cs +++ b/osu.Game/Rulesets/Scoring/HitWindows.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; @@ -30,6 +31,17 @@ namespace osu.Game.Rulesets.Scoring private double meh; private double miss; + /// + /// An empty with only and . + /// No time values are provided (meaning instantaneous hit or miss). + /// + public static HitWindows Empty => new EmptyHitWindows(); + + public HitWindows() + { + Debug.Assert(GetRanges().Length >= 1, $"{nameof(HitWindows)}"); + } + /// /// Retrieves the with the largest hit window that produces a successful hit. /// @@ -168,6 +180,29 @@ namespace osu.Game.Rulesets.Scoring /// Defaults are provided but can be overridden to customise for a ruleset. /// protected virtual DifficultyRange[] GetRanges() => base_ranges; + + public class EmptyHitWindows : HitWindows + { + private static readonly DifficultyRange[] ranges = + { + new DifficultyRange(HitResult.Perfect, 0, 0, 0), + new DifficultyRange(HitResult.Miss, 0, 0, 0), + }; + + public override bool IsHitResultAllowed(HitResult result) + { + switch (result) + { + case HitResult.Great: + case HitResult.Miss: + return true; + } + + return false; + } + + protected override DifficultyRange[] GetRanges() => ranges; + } } public struct DifficultyRange diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index d68b0e94c5..d5b3df27df 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -426,11 +426,11 @@ namespace osu.Game.Rulesets.UI { foreach (var h in Objects) { - if (h.HitWindows != null) + if (h.HitWindows.WindowFor(HitResult.Miss) > 0) return h.HitWindows; foreach (var n in h.NestedHitObjects) - if (n.HitWindows != null) + if (h.HitWindows.WindowFor(HitResult.Miss) > 0) return n.HitWindows; } diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 920d11c910..54556f8648 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Play.HUD private void onNewJudgement(JudgementResult result) { - if (result.HitObject.HitWindows == null) + if (result.HitObject.HitWindows.WindowFor(HitResult.Miss) == 0) return; foreach (var c in Children) From ad6b8d3e04eccee5eaabf496b7b3df2d77c79659 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:08:55 +0900 Subject: [PATCH 319/966] Add result offset bounding to result itself, rather than just transforms --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index f8bc74b2a6..7f3bfd3b5c 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { UpdateInitialTransforms(); - var judgementOffset = Math.Min(HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? double.MaxValue, Result?.TimeOffset ?? 0); + var judgementOffset = Result?.TimeOffset ?? 0; using (BeginDelayedSequence(InitialLifetimeOffset + judgementOffset, true)) { @@ -379,7 +379,8 @@ namespace osu.Game.Rulesets.Objects.Drawables // Ensure that the judgement is given a valid time offset, because this may not get set by the caller var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; - Result.TimeOffset = Time.Current - endTime; + + Result.TimeOffset = Math.Min(HitObject.HitWindows.WindowFor(HitResult.Miss), Time.Current - endTime); switch (Result.Type) { From 9f2a64843291fbe2e8dae6f86f8004559b75991b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:23:37 +0900 Subject: [PATCH 320/966] Add full asserts --- osu.Game/Rulesets/Scoring/HitWindows.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs index 9e7e594104..93e4dfc5fa 100644 --- a/osu.Game/Rulesets/Scoring/HitWindows.cs +++ b/osu.Game/Rulesets/Scoring/HitWindows.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; @@ -39,7 +40,8 @@ namespace osu.Game.Rulesets.Scoring public HitWindows() { - Debug.Assert(GetRanges().Length >= 1, $"{nameof(HitWindows)}"); + Debug.Assert(GetRanges().Any(r => r.Result == HitResult.Miss), $"{nameof(GetRanges)} should always contain {nameof(HitResult.Miss)}"); + Debug.Assert(GetRanges().Any(r => r.Result != HitResult.Miss), $"{nameof(GetRanges)} should always contain at least one result type other than {nameof(HitResult.Miss)}."); } /// From 7e3c97f4962e0503b16527d13cc2fb545a3dc659 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 13:37:07 +0300 Subject: [PATCH 321/966] Implement DeletedChildsPlaceholder component --- .../Online/TestSceneCommentsContainer.cs | 6 ++ .../Online/API/Requests/Responses/Comment.cs | 18 +++++ osu.Game/Overlays/Comments/DrawableComment.cs | 66 +++++++++++++++++-- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 4187771963..8a6ec81d8e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -40,6 +40,12 @@ namespace osu.Game.Tests.Visual.Online scrollFlow.Clear(); scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); }); + + AddStep("Airman comments", () => + { + scrollFlow.Clear(); + scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 24313)); + }); } } } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 76a322e5c9..6fea994cb9 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using osu.Game.Users; using System; using System.Collections.Generic; +using System.Linq; namespace osu.Game.Online.API.Requests.Responses { @@ -91,5 +92,22 @@ namespace osu.Game.Online.API.Requests.Responses { return IsDeleted ? @"deleted" : MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); } + + public int GetDeletedChildsCount() + { + int count = 0; + + if (ChildComments.Any()) + ChildComments.ForEach(child => + { + if (child.IsDeleted) + count++; + }); + + if (IsDeleted) + count++; + + return count; + } } } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4092cbb177..60cae8c62a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -27,6 +27,7 @@ namespace osu.Game.Overlays.Comments private const int message_padding = 40; private const int duration = 200; private const float separator_height = 1.5f; + private const int deleted_placeholder_margin = 80; public readonly BindableBool ShowDeleted = new BindableBool(); @@ -161,12 +162,26 @@ namespace osu.Game.Overlays.Comments AutoSizeDuration = duration, AutoSizeEasing = Easing.OutQuint, Masking = true, - Child = childCommentsContainer = new FillFlowContainer + Child = new FillFlowContainer { - Margin = new MarginPadding { Left = child_margin }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + childCommentsContainer = new FillFlowContainer + { + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + }, + new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) + { + Margin = new MarginPadding { Bottom = margin, Left = deleted_placeholder_margin }, + ShowDeleted = { BindTarget = ShowDeleted } + } + } } } } @@ -221,7 +236,8 @@ namespace osu.Game.Overlays.Comments } } - comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c))); + comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c) + { ShowDeleted = { BindTarget = ShowDeleted } })); } protected override void LoadComplete() @@ -258,6 +274,48 @@ namespace osu.Game.Overlays.Comments } } + private class DeletedChildsPlaceholder : FillFlowContainer + { + public readonly BindableBool ShowDeleted = new BindableBool(); + + private readonly bool canBeVisible; + + public DeletedChildsPlaceholder(int count) + { + canBeVisible = count != 0; + + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(3, 0); + Alpha = 0; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Trash, + Size = new Vector2(14), + }, + new SpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = $@"{count} deleted comments" + } + }; + } + + protected override void LoadComplete() + { + ShowDeleted.BindValueChanged(onShowDeletedChanged, true); + base.LoadComplete(); + } + + private void onShowDeletedChanged(ValueChangedEvent showDeleted) + { + if (canBeVisible) + this.FadeTo(showDeleted.NewValue ? 0 : 1); + } + } + private class ChevronButton : ShowChildsButton { private readonly SpriteIcon icon; From e6f857d0d8db175f6cae7b70df070227fb474387 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:03:20 +0900 Subject: [PATCH 322/966] Revert "Warn on incorrect null usage" This reverts commit 93d2c3d7a1c43cb9871f1bcb779b51cddcc086e9. --- osu.sln.DotSettings | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index ae08a1666f..ed162eed6e 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -17,8 +17,7 @@ WARNING WARNING HINT - - True + HINT HINT HINT WARNING @@ -739,7 +738,6 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - True True True From c9d5bea0f1bd1a8a01c4fe2f08242e8292dffe22 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 13:45:14 +0300 Subject: [PATCH 323/966] Remove animations --- osu.Game/Overlays/Comments/DrawableComment.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 60cae8c62a..94ec7a861a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -25,7 +25,6 @@ namespace osu.Game.Overlays.Comments private const int child_margin = 20; private const int chevron_margin = 30; private const int message_padding = 40; - private const int duration = 200; private const float separator_height = 1.5f; private const int deleted_placeholder_margin = 80; @@ -159,8 +158,6 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - AutoSizeDuration = duration, - AutoSizeEasing = Easing.OutQuint, Masking = true, Child = new FillFlowContainer { @@ -249,14 +246,12 @@ namespace osu.Game.Overlays.Comments private void onChildExpandedChanged(ValueChangedEvent expanded) { - childCommentsVisibilityContainer.ClearTransforms(); - if (expanded.NewValue) childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; else { childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; - childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); + childCommentsVisibilityContainer.ResizeHeightTo(0); } } From 4e273fc628d2bea152dc93f65e9cdbf144c9c610 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:50:05 +0900 Subject: [PATCH 324/966] Return correct allowed value for Perfect Co-Authored-By: Salman Ahmed --- osu.Game/Rulesets/Scoring/HitWindows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs index 93e4dfc5fa..39d67f1071 100644 --- a/osu.Game/Rulesets/Scoring/HitWindows.cs +++ b/osu.Game/Rulesets/Scoring/HitWindows.cs @@ -195,7 +195,7 @@ namespace osu.Game.Rulesets.Scoring { switch (result) { - case HitResult.Great: + case HitResult.Perfect: case HitResult.Miss: return true; } From 107d39c3e97edb17e56bc9377d7e6cf76574ed43 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 14:10:05 +0300 Subject: [PATCH 325/966] Add DeletedChildsPlaceholder to the bottom of the comments container --- .../Online/TestSceneCommentsContainer.cs | 3 +- .../Online/API/Requests/Responses/Comment.cs | 3 - .../Overlays/Comments/CommentsContainer.cs | 13 +++++ .../Comments/DeletedChildsPlaceholder.cs | 58 +++++++++++++++++++ osu.Game/Overlays/Comments/DrawableComment.cs | 46 +-------------- 5 files changed, 75 insertions(+), 48 deletions(-) create mode 100644 osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 8a6ec81d8e..342ba487f0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -21,7 +21,8 @@ namespace osu.Game.Tests.Visual.Online typeof(DrawableComment), typeof(HeaderButton), typeof(SortSelector), - typeof(ShowChildsButton) + typeof(ShowChildsButton), + typeof(DeletedChildsPlaceholder) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 6fea994cb9..2334c86519 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -104,9 +104,6 @@ namespace osu.Game.Online.API.Requests.Responses count++; }); - if (IsDeleted) - count++; - return count; } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index fb97f08a6e..bf68457988 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -93,6 +93,19 @@ namespace osu.Game.Overlays.Comments content.Add(new DrawableComment(c) { ShowDeleted = { BindTarget = ShowDeleted } }); } + + int deletedComments = 0; + + response.Comments.ForEach(comment => + { + if (comment.IsDeleted && comment.IsTopLevel) + deletedComments++; + }); + + content.Add(new DeletedChildsPlaceholder(deletedComments) + { + ShowDeleted = { BindTarget = ShowDeleted } + }); } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs new file mode 100644 index 0000000000..d0e6c17ccb --- /dev/null +++ b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs @@ -0,0 +1,58 @@ +// 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.Containers; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Comments +{ + public class DeletedChildsPlaceholder : FillFlowContainer + { + private const int deleted_placeholder_margin = 80; + private const int margin = 10; + + public readonly BindableBool ShowDeleted = new BindableBool(); + + private readonly bool canBeVisible; + + public DeletedChildsPlaceholder(int count) + { + canBeVisible = count != 0; + + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(3, 0); + Margin = new MarginPadding { Vertical = margin, Left = deleted_placeholder_margin }; + Alpha = 0; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Trash, + Size = new Vector2(14), + }, + new SpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = $@"{count} deleted comments" + } + }; + } + + protected override void LoadComplete() + { + ShowDeleted.BindValueChanged(onShowDeletedChanged, true); + base.LoadComplete(); + } + + private void onShowDeletedChanged(ValueChangedEvent showDeleted) + { + if (canBeVisible) + this.FadeTo(showDeleted.NewValue ? 0 : 1); + } + } +} diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 94ec7a861a..4af2e07227 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -26,7 +26,6 @@ namespace osu.Game.Overlays.Comments private const int chevron_margin = 30; private const int message_padding = 40; private const float separator_height = 1.5f; - private const int deleted_placeholder_margin = 80; public readonly BindableBool ShowDeleted = new BindableBool(); @@ -175,7 +174,6 @@ namespace osu.Game.Overlays.Comments }, new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) { - Margin = new MarginPadding { Bottom = margin, Left = deleted_placeholder_margin }, ShowDeleted = { BindTarget = ShowDeleted } } } @@ -214,6 +212,8 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, Height = separator_height, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, Child = new Box { RelativeSizeAxes = Axes.Both, @@ -269,48 +269,6 @@ namespace osu.Game.Overlays.Comments } } - private class DeletedChildsPlaceholder : FillFlowContainer - { - public readonly BindableBool ShowDeleted = new BindableBool(); - - private readonly bool canBeVisible; - - public DeletedChildsPlaceholder(int count) - { - canBeVisible = count != 0; - - AutoSizeAxes = Axes.Both; - Direction = FillDirection.Horizontal; - Spacing = new Vector2(3, 0); - Alpha = 0; - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.Trash, - Size = new Vector2(14), - }, - new SpriteText - { - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = $@"{count} deleted comments" - } - }; - } - - protected override void LoadComplete() - { - ShowDeleted.BindValueChanged(onShowDeletedChanged, true); - base.LoadComplete(); - } - - private void onShowDeletedChanged(ValueChangedEvent showDeleted) - { - if (canBeVisible) - this.FadeTo(showDeleted.NewValue ? 0 : 1); - } - } - private class ChevronButton : ShowChildsButton { private readonly SpriteIcon icon; From f74c79c2b85422fda49a147c2ee0d9441bbd49df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 Oct 2019 11:58:43 +0900 Subject: [PATCH 326/966] Fix audio playback position being reset after resuming to song select --- .../Visual/Menus/TestSceneScreenNavigation.cs | 80 ++++++++++++++----- osu.Game/Screens/Select/SongSelect.cs | 12 ++- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index 17535cae98..124d3bb453 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -5,12 +5,15 @@ using System; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; @@ -18,7 +21,9 @@ using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Screens; using osu.Game.Screens.Menu; +using osu.Game.Screens.Play; using osu.Game.Screens.Select; +using osu.Game.Tests.Beatmaps.IO; using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -31,11 +36,11 @@ namespace osu.Game.Tests.Visual.Menus private const float click_padding = 25; private GameHost host; - private TestOsuGame osuGame; + private TestOsuGame game; - private Vector2 backButtonPosition => osuGame.ToScreenSpace(new Vector2(click_padding, osuGame.LayoutRectangle.Bottom - click_padding)); + private Vector2 backButtonPosition => game.ToScreenSpace(new Vector2(click_padding, game.LayoutRectangle.Bottom - click_padding)); - private Vector2 optionsButtonPosition => osuGame.ToScreenSpace(new Vector2(click_padding, click_padding)); + private Vector2 optionsButtonPosition => game.ToScreenSpace(new Vector2(click_padding, click_padding)); [BackgroundDependencyLoader] private void load(GameHost host) @@ -54,23 +59,23 @@ namespace osu.Game.Tests.Visual.Menus { AddStep("Create new game instance", () => { - if (osuGame != null) + if (game != null) { - Remove(osuGame); - osuGame.Dispose(); + Remove(game); + game.Dispose(); } - osuGame = new TestOsuGame(LocalStorage, API); - osuGame.SetHost(host); + game = new TestOsuGame(LocalStorage, API); + game.SetHost(host); // todo: this can be removed once we can run audio trakcs without a device present // see https://github.com/ppy/osu/issues/1302 - osuGame.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles); + game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles); - Add(osuGame); + Add(game); }); - AddUntilStep("Wait for load", () => osuGame.IsLoaded); - AddUntilStep("Wait for intro", () => osuGame.ScreenStack.CurrentScreen is IntroScreen); + AddUntilStep("Wait for load", () => game.IsLoaded); + AddUntilStep("Wait for intro", () => game.ScreenStack.CurrentScreen is IntroScreen); confirmAtMainMenu(); } @@ -82,11 +87,39 @@ namespace osu.Game.Tests.Visual.Menus pushAndConfirm(() => songSelect = new TestSongSelect()); AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show()); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); - AddStep("Press escape", () => pressAndRelease(Key.Escape)); + pushEscape(); AddAssert("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden); exitViaEscapeAndConfirm(); } + [Test] + public void TestSongContinuesAfterExitPlayer() + { + Player player = null; + + WorkingBeatmap beatmap() => game.Beatmap.Value; + Track track() => beatmap().Track; + + pushAndConfirm(() => new TestSongSelect()); + + AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(game).Wait()); + + AddUntilStep("wait for selected", () => !(track() is TrackVirtual)); + + AddStep("press enter", () => pressAndRelease(Key.Enter)); + + AddUntilStep("wait for player", () => (player = game.ScreenStack.CurrentScreen as Player) != null); + AddUntilStep("wait for fail", () => player.HasFailed); + + AddUntilStep("wait for track stop", () => !track().IsRunning); + AddAssert("Ensure time before preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime); + + pushEscape(); + + AddUntilStep("wait for track playing", () => track().IsRunning); + AddAssert("Ensure time wasn't reset to preview point", () => track().CurrentTime < beatmap().Metadata.PreviewTime); + } + [Test] public void TestExitSongSelectWithClick() { @@ -98,7 +131,7 @@ namespace osu.Game.Tests.Visual.Menus AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition)); // BackButton handles hover using its child button, so this checks whether or not any of BackButton's children are hovered. - AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == osuGame.BackButton)); + AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == game.BackButton)); AddStep("Click back button", () => InputManager.Click(MouseButton.Left)); AddUntilStep("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden); @@ -122,25 +155,28 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestOpenOptionsAndExitWithEscape() { - AddUntilStep("Wait for options to load", () => osuGame.Settings.IsLoaded); + AddUntilStep("Wait for options to load", () => game.Settings.IsLoaded); AddStep("Enter menu", () => pressAndRelease(Key.Enter)); AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition)); AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left)); - AddAssert("Options overlay was opened", () => osuGame.Settings.State.Value == Visibility.Visible); + AddAssert("Options overlay was opened", () => game.Settings.State.Value == Visibility.Visible); AddStep("Hide options overlay using escape", () => pressAndRelease(Key.Escape)); - AddAssert("Options overlay was closed", () => osuGame.Settings.State.Value == Visibility.Hidden); + AddAssert("Options overlay was closed", () => game.Settings.State.Value == Visibility.Hidden); } private void pushAndConfirm(Func newScreen) { Screen screen = null; - AddStep("Push new screen", () => osuGame.ScreenStack.Push(screen = newScreen())); - AddUntilStep("Wait for new screen", () => osuGame.ScreenStack.CurrentScreen == screen && screen.IsLoaded); + AddStep("Push new screen", () => game.ScreenStack.Push(screen = newScreen())); + AddUntilStep("Wait for new screen", () => game.ScreenStack.CurrentScreen == screen && screen.IsLoaded); } + private void pushEscape() => + AddStep("Press escape", () => pressAndRelease(Key.Escape)); + private void exitViaEscapeAndConfirm() { - AddStep("Press escape", () => pressAndRelease(Key.Escape)); + pushEscape(); confirmAtMainMenu(); } @@ -151,7 +187,7 @@ namespace osu.Game.Tests.Visual.Menus confirmAtMainMenu(); } - private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => osuGame.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded); + private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => game.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded); private void pressAndRelease(Key key) { @@ -169,6 +205,8 @@ namespace osu.Game.Tests.Visual.Menus public new OsuConfigManager LocalConfig => base.LocalConfig; + public new Bindable Beatmap => base.Beatmap; + protected override Loader CreateLoader() => new TestLoader(); public TestOsuGame(Storage storage, IAPIProvider api) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6c5f64ed6c..0025188ad4 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -490,7 +490,7 @@ namespace osu.Game.Screens.Select if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) { UpdateBeatmap(Beatmap.Value); - ensurePlayingSelected(); + ensurePlayingSelected(false); } base.OnResuming(last); @@ -587,7 +587,8 @@ namespace osu.Game.Screens.Select /// Ensures some music is playing for the current track. /// Will resume playback from a manual user pause if the track has changed. ///
- private void ensurePlayingSelected() + /// Whether to restart from the preview point, rather than resuming from previous location. + private void ensurePlayingSelected(bool fromPreviewPoint = true) { Track track = Beatmap.Value.Track; @@ -596,7 +597,12 @@ namespace osu.Game.Screens.Select track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; if (!track.IsRunning && (music?.IsUserPaused != true || isNewTrack)) - track.Restart(); + { + if (fromPreviewPoint) + track.Restart(); + else + track.Start(); + } lastTrack.SetTarget(track); } From e66f9adb8653a68b570d7fbee47f8854a7f61084 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 Oct 2019 16:52:51 +0900 Subject: [PATCH 327/966] Fix user pause not being cancelled when playing audio --- osu.Game/Overlays/MusicController.cs | 45 ++++++++++++++++++--------- osu.Game/Screens/Select/SongSelect.cs | 7 +---- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index f5c36a9cac..2547d7515e 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -98,20 +98,13 @@ namespace osu.Game.Overlays /// /// Start playing the current track (if not already playing). /// - public void Play() - { - if (!IsPlaying) - TogglePause(); - } - - /// - /// Toggle pause / play. - /// /// Whether the operation was successful. - public bool TogglePause() + public bool Play(bool restart = false) { var track = current?.Track; + IsUserPaused = false; + if (track == null) { if (beatmap.Disabled) @@ -121,16 +114,40 @@ namespace osu.Game.Overlays return true; } + if (restart) + track.Restart(); + else if (!IsPlaying) + track.Start(); + + return true; + } + + /// + /// Stop playing the current track and pause at the current position. + /// + public void Stop() + { + var track = current?.Track; + if (track.IsRunning) { IsUserPaused = true; track.Stop(); } + } + + /// + /// Toggle pause / play. + /// + /// Whether the operation was successful. + public bool TogglePause() + { + var track = current?.Track; + + if (track?.IsRunning == true) + Stop(); else - { - track.Start(); - IsUserPaused = false; - } + Play(); return true; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0025188ad4..8187dd04d1 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -597,12 +597,7 @@ namespace osu.Game.Screens.Select track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; if (!track.IsRunning && (music?.IsUserPaused != true || isNewTrack)) - { - if (fromPreviewPoint) - track.Restart(); - else - track.Start(); - } + music?.Play(fromPreviewPoint); lastTrack.SetTarget(track); } From 65df7902f3f933baa68df1df3211f0077147b40f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2019 08:15:47 +0000 Subject: [PATCH 328/966] Bump ppy.osu.Framework.NativeLibs from 2019.813.0 to 2019.1010.0 Bumps [ppy.osu.Framework.NativeLibs](https://github.com/ppy/osu-framework) from 2019.813.0 to 2019.1010.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.813.0...2019.1010.0) Signed-off-by: dependabot-preview[bot] --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index a15cae55c4..e59f613c98 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -124,6 +124,6 @@ - +
From efa5cedf4fef1c3393fdb6ef5926873072c8e6c5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2019 08:16:07 +0000 Subject: [PATCH 329/966] Bump ppy.osu.Framework.Android from 2019.930.0 to 2019.1010.0 Bumps [ppy.osu.Framework.Android](https://github.com/ppy/osu-framework) from 2019.930.0 to 2019.1010.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.930.0...2019.1010.0) Signed-off-by: dependabot-preview[bot] --- osu.Android.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android.props b/osu.Android.props index 51245351b6..fa940a7c89 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -62,6 +62,6 @@ - + From bc4c1a237140da50f9958fcaf3ee7b0535e945db Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2019 08:16:28 +0000 Subject: [PATCH 330/966] Bump ppy.osu.Framework from 2019.930.0 to 2019.1010.0 Bumps [ppy.osu.Framework](https://github.com/ppy/osu-framework) from 2019.930.0 to 2019.1010.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.930.0...2019.1010.0) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8cbc8b0af3..4e3130b64c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index a15cae55c4..8a9dc01f38 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,7 +118,7 @@ - + From e50d8419fda384b0f57a11e0bf4d838ab66d8783 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2019 08:30:37 +0000 Subject: [PATCH 331/966] Bump ppy.osu.Framework.iOS from 2019.930.0 to 2019.1010.0 Bumps [ppy.osu.Framework.iOS](https://github.com/ppy/osu-framework) from 2019.930.0 to 2019.1010.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.930.0...2019.1010.0) Signed-off-by: dependabot-preview[bot] --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index a15cae55c4..7069960ce1 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -119,7 +119,7 @@ - + From 8df2e359c48d458cebaa3923e9d7342428259be2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 Oct 2019 17:39:41 +0900 Subject: [PATCH 332/966] Fix tests on CI --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 4 ++-- osu.Game.Tests/Resources/TestResources.cs | 6 +++--- osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 6da8d8cb71..b24171a231 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -456,9 +456,9 @@ namespace osu.Game.Tests.Beatmaps.IO } } - public static async Task LoadOszIntoOsu(OsuGameBase osu, string path = null) + public static async Task LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false) { - var temp = path ?? TestResources.GetTestBeatmapForImport(); + var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack); var manager = osu.Dependencies.Get(); diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index 9cb85a63bf..66084a3204 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -11,13 +11,13 @@ namespace osu.Game.Tests.Resources { public static Stream OpenResource(string name) => new DllResourceStore("osu.Game.Tests.dll").GetStream($"Resources/{name}"); - public static Stream GetTestBeatmapStream() => new DllResourceStore("osu.Game.Resources.dll").GetStream("Beatmaps/241526 Soleily - Renatus.osz"); + public static Stream GetTestBeatmapStream(bool virtualTrack = false) => new DllResourceStore("osu.Game.Resources.dll").GetStream($"Beatmaps/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz"); - public static string GetTestBeatmapForImport() + public static string GetTestBeatmapForImport(bool virtualTrack = false) { var temp = Path.GetTempFileName() + ".osz"; - using (var stream = GetTestBeatmapStream()) + using (var stream = GetTestBeatmapStream(virtualTrack)) using (var newFile = File.Create(temp)) stream.CopyTo(newFile); diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs index 124d3bb453..e74992e37a 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs @@ -102,9 +102,9 @@ namespace osu.Game.Tests.Visual.Menus pushAndConfirm(() => new TestSongSelect()); - AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(game).Wait()); + AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Wait()); - AddUntilStep("wait for selected", () => !(track() is TrackVirtual)); + AddUntilStep("wait for selected", () => !game.Beatmap.IsDefault); AddStep("press enter", () => pressAndRelease(Key.Enter)); From f6b78ad6617508f49654c86696585b934c83a8d2 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 10 Oct 2019 11:43:45 +0300 Subject: [PATCH 333/966] Overall cleanups --- .../Online/API/Requests/GetCommentsRequest.cs | 8 +-- .../Overlays/Comments/CommentsContainer.cs | 4 +- osu.Game/Overlays/Comments/CommentsHeader.cs | 3 +- .../Comments/DeletedChildsPlaceholder.cs | 3 +- osu.Game/Overlays/Comments/DrawableComment.cs | 59 +++++++------------ osu.Game/Overlays/Comments/SortSelector.cs | 8 ++- 6 files changed, 35 insertions(+), 50 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs index 02a36f7aa2..fb30130ee9 100644 --- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -4,6 +4,7 @@ using osu.Framework.IO.Network; using Humanizer; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Comments; namespace osu.Game.Online.API.Requests { @@ -43,11 +44,4 @@ namespace osu.Game.Online.API.Requests Beatmapset, NewsPost } - - public enum SortCommentsBy - { - New, - Old, - Top - } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index bf68457988..314376f5ff 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -91,7 +91,9 @@ namespace osu.Game.Overlays.Comments { if (c.IsTopLevel) content.Add(new DrawableComment(c) - { ShowDeleted = { BindTarget = ShowDeleted } }); + { + ShowDeleted = { BindTarget = ShowDeleted } + }); } int deletedComments = 0; diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index 90a6f44d6b..6e9864f153 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; -using osu.Game.Online.API.Requests; using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; @@ -62,7 +61,7 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Current = { BindTarget = Sort } + Current = Sort } } }, diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs index d0e6c17ccb..7aae42908e 100644 --- a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs @@ -7,6 +7,7 @@ using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; using osu.Framework.Bindables; +using System.Linq; namespace osu.Game.Overlays.Comments { @@ -38,7 +39,7 @@ namespace osu.Game.Overlays.Comments new SpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = $@"{count} deleted comments" + Text = $@"{count} deleted comment{(count.ToString().ToCharArray().Last() == '1' ? "" : "s")}" } }; } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4af2e07227..fd7f874304 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Comments private readonly BindableBool childExpanded = new BindableBool(true); - private readonly Container childCommentsVisibilityContainer; + private readonly FillFlowContainer childCommentsVisibilityContainer; private readonly Comment comment; public DrawableComment(Comment comment) @@ -47,7 +47,6 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Masking = true; InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -145,7 +144,9 @@ namespace osu.Game.Overlays.Comments Text = HumanizerUtils.Humanize(comment.CreatedAt) }, new RepliesButton(comment.RepliesCount) - { Expanded = { BindTarget = childExpanded } }, + { + Expanded = { BindTarget = childExpanded } + }, } } } @@ -153,29 +154,23 @@ namespace osu.Game.Overlays.Comments } } }, - childCommentsVisibilityContainer = new Container + childCommentsVisibilityContainer = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Masking = true, - Child = new FillFlowContainer + Direction = FillDirection.Vertical, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] + childCommentsContainer = new FillFlowContainer { - childCommentsContainer = new FillFlowContainer - { - Margin = new MarginPadding { Left = child_margin }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical - }, - new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) - { - ShowDeleted = { BindTarget = ShowDeleted } - } + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + }, + new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) + { + ShowDeleted = { BindTarget = ShowDeleted } } } } @@ -234,7 +229,9 @@ namespace osu.Game.Overlays.Comments } comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c) - { ShowDeleted = { BindTarget = ShowDeleted } })); + { + ShowDeleted = { BindTarget = ShowDeleted } + })); } protected override void LoadComplete() @@ -246,27 +243,13 @@ namespace osu.Game.Overlays.Comments private void onChildExpandedChanged(ValueChangedEvent expanded) { - if (expanded.NewValue) - childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; - else - { - childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; - childCommentsVisibilityContainer.ResizeHeightTo(0); - } + childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0); } private void onShowDeletedChanged(ValueChangedEvent show) { if (comment.IsDeleted) - { - if (show.NewValue) - AutoSizeAxes = Axes.Y; - else - { - AutoSizeAxes = Axes.None; - this.ResizeHeightTo(0); - } - } + this.FadeTo(show.NewValue ? 1 : 0); } private class ChevronButton : ShowChildsButton diff --git a/osu.Game/Overlays/Comments/SortSelector.cs b/osu.Game/Overlays/Comments/SortSelector.cs index 4425145c3e..cb95a758ff 100644 --- a/osu.Game/Overlays/Comments/SortSelector.cs +++ b/osu.Game/Overlays/Comments/SortSelector.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.Game.Online.API.Requests; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; @@ -72,4 +71,11 @@ namespace osu.Game.Overlays.Comments } } } + + public enum SortCommentsBy + { + New, + Old, + Top + } } From 5d6648d9c95df7f5e05b5008e280f525410ccfe7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 Oct 2019 17:45:38 +0900 Subject: [PATCH 334/966] Update 2.2 references --- .../CatchRuleset__Tests_.xml | 4 +-- .../ManiaRuleset__Tests_.xml | 4 +-- .../runConfigurations/OsuRuleset__Tests_.xml | 4 +-- .../TaikoRuleset__Tests_.xml | 4 +-- .../.idea/runConfigurations/Tournament.xml | 4 +-- .../.idea/runConfigurations/osu_.xml | 4 +-- .../.idea/runConfigurations/osu___Tests_.xml | 4 +-- .vscode/launch.json | 32 +++++++++---------- .vscode/tasks.json | 2 +- README.md | 4 +-- osu.Desktop/osu.Desktop.csproj | 2 +- .../.vscode/launch.json | 4 +-- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../.vscode/launch.json | 4 +-- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- .../.vscode/launch.json | 4 +-- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../.vscode/launch.json | 4 +-- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- .../osu.Game.Tournament.Tests.csproj | 2 +- 21 files changed, 48 insertions(+), 48 deletions(-) diff --git a/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml b/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml index 6463dd6ea5..5372b6f28a 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml @@ -1,6 +1,6 @@ -