From 12c235027df835b189669ade2313f8128b4d31ea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 23 Apr 2020 13:28:27 +0900 Subject: [PATCH 01/57] Remove stale file --- .../Edit/Masks/ManiaSelectionBlueprint.cs | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs deleted file mode 100644 index 433db79ae0..0000000000 --- a/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs +++ /dev/null @@ -1,18 +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; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Objects.Drawables; - -namespace osu.Game.Rulesets.Mania.Edit.Masks -{ - public abstract class ManiaSelectionBlueprint : OverlaySelectionBlueprint - { - protected ManiaSelectionBlueprint(DrawableHitObject drawableObject) - : base(drawableObject) - { - RelativeSizeAxes = Axes.None; - } - } -} From 0a840a26133b76a1bbd80b9d77782843460e28d9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 23 Apr 2020 17:41:33 +0900 Subject: [PATCH 02/57] Fix mania not getting its own selection handler --- osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs index d744036b4c..cea27498c3 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs @@ -30,5 +30,7 @@ namespace osu.Game.Rulesets.Mania.Edit return base.CreateBlueprintFor(hitObject); } + + protected override SelectionHandler CreateSelectionHandler() => new ManiaSelectionHandler(); } } From 4ebb28d3e7fdc0a412643f5e4a3effce353e9ebe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 23 Apr 2020 17:52:54 +0900 Subject: [PATCH 03/57] wip --- .../Edit/Blueprints/HoldNoteSelectionBlueprint.cs | 2 ++ osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs | 4 ++-- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 7 +++++-- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index d569d68b59..43d43ef252 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -76,5 +76,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints } public override Quad SelectionQuad => ScreenSpaceDrawQuad; + + public override Vector2 SelectionPoint => DrawableObject.Head.ScreenSpaceDrawQuad.Centre; } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 9069a636a8..78f159b733 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Edit var maniaBlueprint = (ManiaSelectionBlueprint)moveEvent.Blueprint; int lastColumn = maniaBlueprint.DrawableObject.HitObject.Column; - adjustOrigins(maniaBlueprint); + // adjustOrigins(maniaBlueprint); performDragMovement(moveEvent); performColumnMovement(lastColumn, moveEvent); @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Edit // When scrolling downwards the anchor position is at the bottom of the screen, however the movement event assumes the anchor is at the top of the screen. // This causes the delta to assume a positive hitobject position, and which can be corrected for by subtracting the parent height. if (scrollingInfo.Direction.Value == ScrollingDirection.Down) - delta -= moveEvent.Blueprint.Parent.DrawHeight; // todo: probably wrong + delta -= moveEvent.Blueprint.Parent.DrawHeight; // todo: definitely wrong foreach (var selectionBlueprint in SelectedBlueprints) { diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index ad16e22e5e..0823be01f8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -401,15 +401,18 @@ namespace osu.Game.Screens.Edit.Compose.Components HitObject draggedObject = movementBlueprint.HitObject; - // The final movement position, relative to screenSpaceMovementStartPosition + // The final movement position, relative to movementBlueprintOriginalPosition Vector2 movePosition = movementBlueprintOriginalPosition.Value + e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; - (Vector2 snappedPosition, double snappedTime) = snapProvider.GetSnappedPosition(ToLocalSpace(movePosition), draggedObject.StartTime); + (Vector2 snappedPosition, _) = snapProvider.GetSnappedPosition(ToLocalSpace(movePosition), draggedObject.StartTime); // Move the hitobjects if (!selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, ToScreenSpace(snappedPosition)))) return true; + // Todo: Temp + (_, double snappedTime) = snapProvider.GetSnappedPosition(ToLocalSpace(snappedPosition), draggedObject.StartTime); + // Apply the start time at the newly snapped-to position double offset = snappedTime - draggedObject.StartTime; foreach (HitObject obj in selectionHandler.SelectedHitObjects) diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index 96e3c037a3..a7c84bf692 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -23,6 +23,7 @@ namespace osu.Game.Tests.Beatmaps HitObjects = baseBeatmap.HitObjects; BeatmapInfo.Ruleset = ruleset; + BeatmapInfo.RulesetID = ruleset.ID ?? 0; BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata; BeatmapInfo.BeatmapSet.Beatmaps = new List { BeatmapInfo }; BeatmapInfo.BeatmapSet.OnlineInfo = new BeatmapSetOnlineInfo From abb687286be341b609ab92705f012f5c9a6a4496 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 23 Apr 2020 22:34:00 -0700 Subject: [PATCH 04/57] Fix score multiplier being cut off in mod select at higher ui scales --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index e9b3598625..b94f5cb570 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -103,7 +103,7 @@ namespace osu.Game.Overlays.Mods { new Dimension(GridSizeMode.Absolute, 90), new Dimension(GridSizeMode.Distributed), - new Dimension(GridSizeMode.Absolute, 70), + new Dimension(GridSizeMode.AutoSize), }, Content = new[] { @@ -197,7 +197,8 @@ namespace osu.Game.Overlays.Mods // Footer new Container { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Children = new Drawable[] @@ -215,7 +216,6 @@ namespace osu.Game.Overlays.Mods AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Width = content_width, - Direction = FillDirection.Horizontal, Padding = new MarginPadding { Vertical = 15, From 118db03b56ec35eba67b900b930a73d61838e191 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 23 Apr 2020 22:41:38 -0700 Subject: [PATCH 05/57] Fix vertical spacing and score multiplier splitting apart Also cleans up margin and its hacks (alignment done with anchor/origin now). --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 73 +++++++++++----------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index b94f5cb570..6ab72bc02a 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -57,6 +57,8 @@ namespace osu.Game.Overlays.Mods protected Color4 HighMultiplierColour; private const float content_width = 0.8f; + private const float footer_button_spacing = 20; + private readonly FillFlowContainer footerContainer; private SampleChannel sampleOn, sampleOff; @@ -216,6 +218,7 @@ namespace osu.Game.Overlays.Mods AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Width = content_width, + Spacing = new Vector2(footer_button_spacing, footer_button_spacing / 2), Padding = new MarginPadding { Vertical = 15, @@ -228,10 +231,8 @@ namespace osu.Game.Overlays.Mods Width = 180, Text = "Deselect All", Action = DeselectAll, - Margin = new MarginPadding - { - Right = 20 - } + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, }, CustomiseButton = new TriangleButton { @@ -239,49 +240,47 @@ namespace osu.Game.Overlays.Mods Text = "Customisation", Action = () => ModSettingsContainer.Alpha = ModSettingsContainer.Alpha == 1 ? 0 : 1, Enabled = { Value = false }, - Margin = new MarginPadding - { - Right = 20 - } + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, }, CloseButton = new TriangleButton { Width = 180, Text = "Close", Action = Hide, - Margin = new MarginPadding - { - Right = 20 - } + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, }, - new OsuSpriteText + new FillFlowContainer { - Text = @"Score Multiplier:", - Font = OsuFont.GetFont(size: 30), - Margin = new MarginPadding + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(footer_button_spacing / 2, 0), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Children = new Drawable[] { - Top = 5, - Right = 10 - } + new OsuSpriteText + { + Text = @"Score Multiplier:", + Font = OsuFont.GetFont(size: 30), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + }, + MultiplierLabel = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold, fixedWidth: true), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + }, + UnrankedLabel = new OsuSpriteText + { + Text = @"(Unranked)", + Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold), + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + }, + }, }, - MultiplierLabel = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold), - Margin = new MarginPadding - { - Top = 5 - } - }, - UnrankedLabel = new OsuSpriteText - { - Text = @"(Unranked)", - Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold), - Margin = new MarginPadding - { - Top = 5, - Left = 10 - } - } } } }, From 0f6ec274f9547881484b73559e6d27a0e709eaad Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 23 Apr 2020 22:44:17 -0700 Subject: [PATCH 06/57] Add transitions to footer when flowing to another row --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 6ab72bc02a..a7b7e50422 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -219,6 +219,8 @@ namespace osu.Game.Overlays.Mods RelativeSizeAxes = Axes.X, Width = content_width, Spacing = new Vector2(footer_button_spacing, footer_button_spacing / 2), + LayoutDuration = 100, + LayoutEasing = Easing.OutQuint, Padding = new MarginPadding { Vertical = 15, From 4b60be87b591a2bb6d8b1b5378790e7a0509e478 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 24 Apr 2020 16:34:41 -0700 Subject: [PATCH 07/57] Move unranked label under multiplier number to avoid width changes --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index a7b7e50422..36d21c8b46 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -268,18 +268,30 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, }, - MultiplierLabel = new OsuSpriteText + new FillFlowContainer { - Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold, fixedWidth: true), - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - }, - UnrankedLabel = new OsuSpriteText - { - Text = @"(Unranked)", - Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold), + AutoSizeAxes = Axes.Both, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, + Direction = FillDirection.Vertical, + LayoutDuration = 100, + LayoutEasing = Easing.OutQuint, + Children = new Drawable[] + { + MultiplierLabel = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 25, weight: FontWeight.Bold, fixedWidth: true), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + UnrankedLabel = new OsuSpriteText + { + Text = @"(Unranked)", + Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + } }, }, }, From 8a47a615dbb44c3e236f8b4b61ebe1609a9bcefe Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 26 Apr 2020 19:29:22 -0700 Subject: [PATCH 08/57] Remove unranked label from footer --- .../TestSceneModSelectOverlay.cs | 12 -------- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 29 ++----------------- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 2294cd6966..769c660f48 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -117,8 +117,6 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestManiaMods() { changeRuleset(3); - - testRankedText(new ManiaRuleset().GetModsFor(ModType.Conversion).First(m => m is ManiaModRandom)); } [Test] @@ -217,15 +215,6 @@ namespace osu.Game.Tests.Visual.UserInterface checkLabelColor(() => Color4.White); } - private void testRankedText(Mod mod) - { - AddUntilStep("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); - selectNext(mod); - AddUntilStep("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0); - selectPrevious(mod); - AddUntilStep("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); - } - private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1)); private void selectPrevious(Mod mod) => AddStep($"right click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(-1)); @@ -272,7 +261,6 @@ namespace osu.Game.Tests.Visual.UserInterface } public new OsuSpriteText MultiplierLabel => base.MultiplierLabel; - public new OsuSpriteText UnrankedLabel => base.UnrankedLabel; public new TriangleButton DeselectAllButton => base.DeselectAllButton; public new Color4 LowMultiplierColour => base.LowMultiplierColour; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 36d21c8b46..914e730c27 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -37,7 +37,6 @@ namespace osu.Game.Overlays.Mods protected readonly TriangleButton CloseButton; protected readonly OsuSpriteText MultiplierLabel; - protected readonly OsuSpriteText UnrankedLabel; protected override bool BlockNonPositionalInput => false; @@ -268,30 +267,11 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, }, - new FillFlowContainer + MultiplierLabel = new OsuSpriteText { - AutoSizeAxes = Axes.Both, + Font = OsuFont.GetFont(size: 25, weight: FontWeight.Bold, fixedWidth: true), Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Direction = FillDirection.Vertical, - LayoutDuration = 100, - LayoutEasing = Easing.OutQuint, - Children = new Drawable[] - { - MultiplierLabel = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 25, weight: FontWeight.Bold, fixedWidth: true), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - UnrankedLabel = new OsuSpriteText - { - Text = @"(Unranked)", - Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - } }, }, }, @@ -340,7 +320,6 @@ namespace osu.Game.Overlays.Mods { LowMultiplierColour = colours.Red; HighMultiplierColour = colours.Green; - UnrankedLabel.Colour = colours.Blue; availableMods = osu.AvailableMods.GetBoundCopy(); @@ -444,12 +423,10 @@ namespace osu.Game.Overlays.Mods private void updateMods() { var multiplier = 1.0; - var ranked = true; foreach (var mod in SelectedMods.Value) { multiplier *= mod.ScoreMultiplier; - ranked &= mod.Ranked; } MultiplierLabel.Text = $"{multiplier:N2}x"; @@ -459,8 +436,6 @@ namespace osu.Game.Overlays.Mods MultiplierLabel.FadeColour(LowMultiplierColour, 200); else MultiplierLabel.FadeColour(Color4.White, 200); - - UnrankedLabel.FadeTo(ranked ? 0 : 1, 200); } private void updateModSettings(ValueChangedEvent> selectedMods) From 1b9362041a4e4019c84f41f8230aca4f3d194459 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 26 Apr 2020 19:50:11 -0700 Subject: [PATCH 09/57] Revert multiplier number changes and set width Safe arbitrary width taken from "0.00x" (highest width of 67), rounded to the nearest tenth. --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 914e730c27..09f4befbc1 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -269,9 +269,10 @@ namespace osu.Game.Overlays.Mods }, MultiplierLabel = new OsuSpriteText { - Font = OsuFont.GetFont(size: 25, weight: FontWeight.Bold, fixedWidth: true), + Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold), Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, + Width = 70, // to avoid footer from flowing when clicking mods }, }, }, From 7731d45f13ce88392716c640dbdaa79b23d965ce Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 26 Apr 2020 20:30:56 -0700 Subject: [PATCH 10/57] Remove unnecessary usings --- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 769c660f48..ec6ee6bc83 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -14,8 +14,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Mods.Sections; using osu.Game.Rulesets; -using osu.Game.Rulesets.Mania; -using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; From acf95fca9cdd8b12027d907838738fa0216845b4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 27 Apr 2020 17:14:00 +0900 Subject: [PATCH 11/57] Remove old, now unnecessary method --- .../Edit/ManiaSelectionHandler.cs | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 78f159b733..d290e4ec24 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -35,35 +35,12 @@ namespace osu.Game.Rulesets.Mania.Edit var maniaBlueprint = (ManiaSelectionBlueprint)moveEvent.Blueprint; int lastColumn = maniaBlueprint.DrawableObject.HitObject.Column; - // adjustOrigins(maniaBlueprint); performDragMovement(moveEvent); performColumnMovement(lastColumn, moveEvent); return true; } - /// - /// Ensures that the position of hitobjects remains centred to the mouse position. - /// E.g. The hitobject position will change if the editor scrolls while a hitobject is dragged. - /// - /// The that received the drag event. - private void adjustOrigins(ManiaSelectionBlueprint reference) - { - var referenceParent = (HitObjectContainer)reference.DrawableObject.Parent; - - float offsetFromReferenceOrigin = reference.DragPosition.Y - reference.DrawableObject.OriginPosition.Y; - float targetPosition = referenceParent.ToLocalSpace(reference.ScreenSpaceDragPosition).Y - offsetFromReferenceOrigin; - - // Flip the vertical coordinate space when scrolling downwards - if (scrollingInfo.Direction.Value == ScrollingDirection.Down) - targetPosition -= referenceParent.DrawHeight; - - float movementDelta = targetPosition - reference.DrawableObject.Position.Y; - - foreach (var b in SelectedBlueprints.OfType()) - b.DrawableObject.Y += movementDelta; - } - private void performDragMovement(MoveSelectionEvent moveEvent) { float delta = moveEvent.InstantDelta.Y; From b88dd442526c8a58a9bd992101b5d7b5da33e3a6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 27 Apr 2020 19:47:25 +0900 Subject: [PATCH 12/57] Fix movement not working correctly in down-scroll --- .../Blueprints/ManiaSelectionBlueprint.cs | 20 +++++++++++++++++++ .../Edit/ManiaSelectionHandler.cs | 19 +++++++----------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs index 9f57160f99..14d52dd08e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -74,5 +74,25 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints DrawableObject.AlwaysAlive = false; base.Hide(); } + + public override Vector2 GetInstantDelta(Vector2 screenSpacePosition) + { + var baseDelta = base.GetInstantDelta(screenSpacePosition); + + if (scrollingInfo.Direction.Value == ScrollingDirection.Down) + { + // The parent of DrawableObject is the scrolling hitobject container (SHOC). + // In the coordinate-space of the SHOC, the screen-space position at the hit target is equal to the height of the SHOC, + // but this is not what we want as it means a slight movement downwards results in a delta greater than the height of the SHOC. + // To get around this issue, the height of the SHOC is subtracted from the delta. + // + // Ideally this should be a _negative_ value in the case described above, however this code gives a _positive_ delta. + // This is intentional as the delta is added to the hitobject's position (see: ManiaSelectionHandler) and a negative delta would move them towards the top of the screen instead, + // which would cause the delta to get increasingly larger as additional movements are performed. + return new Vector2(baseDelta.X, baseDelta.Y - DrawableObject.Parent.DrawHeight); + } + + return baseDelta; + } } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index d290e4ec24..8dfc97f87a 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -45,11 +45,6 @@ namespace osu.Game.Rulesets.Mania.Edit { float delta = moveEvent.InstantDelta.Y; - // When scrolling downwards the anchor position is at the bottom of the screen, however the movement event assumes the anchor is at the top of the screen. - // This causes the delta to assume a positive hitobject position, and which can be corrected for by subtracting the parent height. - if (scrollingInfo.Direction.Value == ScrollingDirection.Down) - delta -= moveEvent.Blueprint.Parent.DrawHeight; // todo: definitely wrong - foreach (var selectionBlueprint in SelectedBlueprints) { var b = (OverlaySelectionBlueprint)selectionBlueprint; @@ -57,24 +52,24 @@ namespace osu.Game.Rulesets.Mania.Edit var hitObject = b.DrawableObject; var objectParent = (HitObjectContainer)hitObject.Parent; - // StartTime could be used to adjust the position if only one movement event was received per frame. - // However this is not the case and ScrollingHitObjectContainer performs movement in UpdateAfterChildren() so the position must also be updated to be valid for further movement events + // We receive multiple movement events per frame such that we can't rely on updating the start time + // since the scrolling hitobject container requires at least one update frame to update the position. + // However the position needs to be valid for future movement events to calculate the correct deltas. hitObject.Y += delta; float targetPosition = hitObject.Position.Y; - // The scrolling algorithm always assumes an anchor at the top of the screen, so the position must be flipped when scrolling downwards to reflect a top anchor if (scrollingInfo.Direction.Value == ScrollingDirection.Down) + { + // When scrolling downwards, the position is _negative_ when the object's start time is after the current time (e.g. in the middle of the stage). + // However all scrolling algorithms upwards scrolling, meaning that a positive (inverse) position is expected in the same scenario. targetPosition = -targetPosition; - - objectParent.Remove(hitObject); + } hitObject.HitObject.StartTime = scrollingInfo.Algorithm.TimeAt(targetPosition, editorClock.CurrentTime, scrollingInfo.TimeRange.Value, objectParent.DrawHeight); - - objectParent.Add(hitObject); } } From cebc0fc0466d61db6f22c19358c8d22ce5f12d09 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 27 Apr 2020 20:35:24 +0900 Subject: [PATCH 13/57] Attempt to fix multiple selection movements --- .../Edit/ManiaHitObjectComposer.cs | 28 ++++++++++++++++++- .../Edit/ManiaSelectionHandler.cs | 14 ---------- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 16 +++++++++++ .../Compose/Components/BlueprintContainer.cs | 10 +++---- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 62b609610f..8d012c63ac 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Screens.Edit.Compose.Components; using osuTK; @@ -37,7 +38,32 @@ namespace osu.Game.Rulesets.Mania.Edit protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - public int TotalColumns => ((ManiaPlayfield)drawableRuleset.Playfield).TotalColumns; + public ManiaPlayfield Playfield => ((ManiaPlayfield)drawableRuleset.Playfield); + + public int TotalColumns => Playfield.TotalColumns; + + public override (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time) + { + var hoc = Playfield.GetColumn(0).HitObjectContainer; + + position.Y -= ToLocalSpace(hoc.ScreenSpaceDrawQuad.TopLeft).Y; + + float targetPosition = position.Y; + + if (drawableRuleset.ScrollingInfo.Direction.Value == ScrollingDirection.Down) + { + // When scrolling downwards, the position is _negative_ when the object's start time is after the current time (e.g. in the middle of the stage). + // However all scrolling algorithms upwards scrolling, meaning that a positive (inverse) position is expected in the same scenario. + targetPosition = -targetPosition; + } + + double targetTime = drawableRuleset.ScrollingInfo.Algorithm.TimeAt(targetPosition, + EditorClock.CurrentTime, + drawableRuleset.ScrollingInfo.TimeRange.Value, + hoc.DrawHeight); + + return base.GetSnappedPosition(position, targetTime); + } protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) { diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 8dfc97f87a..989e0f5b01 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -56,20 +56,6 @@ namespace osu.Game.Rulesets.Mania.Edit // since the scrolling hitobject container requires at least one update frame to update the position. // However the position needs to be valid for future movement events to calculate the correct deltas. hitObject.Y += delta; - - float targetPosition = hitObject.Position.Y; - - if (scrollingInfo.Direction.Value == ScrollingDirection.Down) - { - // When scrolling downwards, the position is _negative_ when the object's start time is after the current time (e.g. in the middle of the stage). - // However all scrolling algorithms upwards scrolling, meaning that a positive (inverse) position is expected in the same scenario. - targetPosition = -targetPosition; - } - - hitObject.HitObject.StartTime = scrollingInfo.Algorithm.TimeAt(targetPosition, - editorClock.CurrentTime, - scrollingInfo.TimeRange.Value, - objectParent.DrawHeight); } } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 2dec468654..f9faa262ed 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -87,6 +87,22 @@ namespace osu.Game.Rulesets.Mania.UI return found; } + public Column GetColumn(int index) + { + foreach (var stage in stages) + { + if (index >= stage.Columns.Count) + { + index -= stage.Columns.Count; + continue; + } + + return stage.Columns[index]; + } + + throw new ArgumentOutOfRangeException(nameof(index)); + } + /// /// Retrieves the total amount of columns across all stages in this playfield. /// diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 0823be01f8..8910684463 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -401,18 +401,16 @@ namespace osu.Game.Screens.Edit.Compose.Components HitObject draggedObject = movementBlueprint.HitObject; - // The final movement position, relative to movementBlueprintOriginalPosition + // The final movement position, relative to movementBlueprintOriginalPosition. Vector2 movePosition = movementBlueprintOriginalPosition.Value + e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; - (Vector2 snappedPosition, _) = snapProvider.GetSnappedPosition(ToLocalSpace(movePosition), draggedObject.StartTime); + // Retrieve a snapped position. + (Vector2 snappedPosition, double snappedTime) = snapProvider.GetSnappedPosition(ToLocalSpace(movePosition), draggedObject.StartTime); - // Move the hitobjects + // Move the hitobjects. if (!selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, ToScreenSpace(snappedPosition)))) return true; - // Todo: Temp - (_, double snappedTime) = snapProvider.GetSnappedPosition(ToLocalSpace(snappedPosition), draggedObject.StartTime); - // Apply the start time at the newly snapped-to position double offset = snappedTime - draggedObject.StartTime; foreach (HitObject obj in selectionHandler.SelectedHitObjects) From be59ee945a5ead6fe5d8d7cbeaad058e8180bf7f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Apr 2020 22:22:32 +0900 Subject: [PATCH 14/57] Add taiko hit explosion skinning support --- .../Skinning/TestSceneHitExplosion.cs | 79 +++++++++++++++++++ .../Skinning/LegacyHitExplosion.cs | 29 +++++++ .../Skinning/TaikoLegacySkinTransformer.cs | 27 +++++++ .../TaikoSkinComponents.cs | 5 +- .../UI/DefaultHitExplosion.cs | 54 +++++++++++++ osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 50 ++++++------ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 7 +- 7 files changed, 221 insertions(+), 30 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs create mode 100644 osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs new file mode 100644 index 0000000000..ca0c60b67a --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -0,0 +1,79 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Skinning; +using osu.Game.Rulesets.Taiko.UI; + +namespace osu.Game.Rulesets.Taiko.Tests.Skinning +{ + [TestFixture] + public class TestSceneHitExplosion : TaikoSkinnableTestScene + { + public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] + { + typeof(HitExplosion), + typeof(LegacyHitExplosion), + typeof(DefaultHitExplosion), + }).ToList(); + + [BackgroundDependencyLoader] + private void load() + { + AddStep("Great", () => SetContents(() => getContentFor(HitResult.Great))); + AddStep("Good", () => SetContents(() => getContentFor(HitResult.Good))); + AddStep("Miss", () => SetContents(() => getContentFor(HitResult.Miss))); + } + + private Drawable getContentFor(HitResult type) + { + DrawableTaikoHitObject hit; + + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + hit = createHit(type), + new HitExplosion(hit) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + }; + } + + private DrawableTaikoHitObject createHit(HitResult type) => new TestDrawableHit(new Hit { StartTime = Time.Current }, type); + + private class TestDrawableHit : DrawableTaikoHitObject + { + private readonly HitResult type; + + public TestDrawableHit(Hit hit, HitResult type) + : base(hit) + { + this.type = type; + } + + [BackgroundDependencyLoader] + private void load() + { + Result.Type = type; + } + + public override bool OnPressed(TaikoAction action) => false; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs new file mode 100644 index 0000000000..d29b574866 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.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 osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Rulesets.Taiko.Skinning +{ + public class LegacyHitExplosion : CompositeDrawable + { + public LegacyHitExplosion(Drawable sprite) + { + InternalChild = sprite; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + AutoSizeAxes = Axes.Both; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.FadeIn(120); + this.ScaleTo(0.6f).Then().ScaleTo(1, 240, Easing.OutElastic); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs index 447d6ae455..bea1c6bdcf 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs @@ -81,11 +81,38 @@ namespace osu.Game.Rulesets.Taiko.Skinning return new LegacyBarLine(); return null; + + case TaikoSkinComponents.TaikoExplosionGood: + case TaikoSkinComponents.TaikoExplosionGreat: + case TaikoSkinComponents.TaikoExplosionMiss: + + var sprite = this.GetAnimation(getHitname(taikoComponent.Component), true, false); + if (sprite != null) + return new LegacyHitExplosion(sprite); + + return null; } return source.GetDrawableComponent(component); } + private string getHitname(TaikoSkinComponents component) + { + switch (component) + { + case TaikoSkinComponents.TaikoExplosionMiss: + return "taiko-hit0"; + + case TaikoSkinComponents.TaikoExplosionGood: + return "taiko-hit100"; + + case TaikoSkinComponents.TaikoExplosionGreat: + return "taiko-hit300"; + } + + return string.Empty; + } + public Texture GetTexture(string componentName) => source.GetTexture(componentName); public SampleChannel GetSample(ISampleInfo sampleInfo) => source.GetSample(new LegacyTaikoSampleInfo(sampleInfo)); diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index a90ce608b2..fd091f97d0 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -14,6 +14,9 @@ namespace osu.Game.Rulesets.Taiko HitTarget, PlayfieldBackgroundLeft, PlayfieldBackgroundRight, - BarLine + BarLine, + TaikoExplosionMiss, + TaikoExplosionGood, + TaikoExplosionGreat, } } diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs new file mode 100644 index 0000000000..aa444d0494 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs @@ -0,0 +1,54 @@ +// 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.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.UI +{ + internal class DefaultHitExplosion : CircularContainer + { + [Resolved] + private DrawableHitObject judgedObject { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.Both; + + BorderColour = Color4.White; + BorderThickness = 1; + + Alpha = 0.15f; + Masking = true; + + if (judgedObject.Result.Type == HitResult.Miss) + return; + + bool isRim = (judgedObject.HitObject as Hit)?.Type == HitType.Rim; + + InternalChildren = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = isRim ? colours.BlueDarker : colours.PinkDarker, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.ScaleTo(3f, 1000, Easing.OutQuint); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index fbaae7e322..9bef93d834 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -1,15 +1,15 @@ // 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 osuTK; -using osuTK.Graphics; 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.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.UI { @@ -20,15 +20,12 @@ namespace osu.Game.Rulesets.Taiko.UI { public override bool RemoveWhenNotAlive => true; + [Cached(typeof(DrawableHitObject))] public readonly DrawableHitObject JudgedObject; - private readonly HitType type; - private readonly Box innerFill; - - public HitExplosion(DrawableHitObject judgedObject, HitType type) + public HitExplosion(DrawableHitObject judgedObject) { JudgedObject = judgedObject; - this.type = type; Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -37,35 +34,36 @@ namespace osu.Game.Rulesets.Taiko.UI Size = new Vector2(TaikoHitObject.DEFAULT_SIZE); RelativePositionAxes = Axes.Both; - - BorderColour = Color4.White; - BorderThickness = 1; - - Alpha = 0.15f; - Masking = true; - - Children = new[] - { - innerFill = new Box - { - RelativeSizeAxes = Axes.Both, - } - }; } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { - innerFill.Colour = type == HitType.Rim ? colours.BlueDarker : colours.PinkDarker; + Child = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(JudgedObject.Result?.Type ?? HitResult.Great)), _ => new DefaultHitExplosion()); + } + + private TaikoSkinComponents getComponentName(HitResult resultType) + { + switch (resultType) + { + case HitResult.Miss: + return TaikoSkinComponents.TaikoExplosionMiss; + + case HitResult.Good: + return TaikoSkinComponents.TaikoExplosionGood; + + case HitResult.Great: + return TaikoSkinComponents.TaikoExplosionGreat; + } + + throw new ArgumentException("Invalid result type", nameof(resultType)); } protected override void LoadComplete() { base.LoadComplete(); - this.ScaleTo(3f, 1000, Easing.OutQuint); this.FadeOut(500); - Expire(true); } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 4bc6cb8e4b..6a78c0a1fb 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -185,7 +185,6 @@ namespace osu.Game.Rulesets.Taiko.UI var drawableTick = (DrawableDrumRollTick)judgedObject; addDrumRollHit(drawableTick); - addExplosion(drawableTick, drawableTick.JudgementType); break; default: @@ -200,7 +199,9 @@ namespace osu.Game.Rulesets.Taiko.UI if (!result.IsHit) break; - addExplosion(judgedObject, (judgedObject.HitObject as Hit)?.Type ?? HitType.Centre); + var type = (judgedObject.HitObject as Hit)?.Type ?? HitType.Centre; + + addExplosion(judgedObject, type); break; } } @@ -210,7 +211,7 @@ namespace osu.Game.Rulesets.Taiko.UI private void addExplosion(DrawableHitObject drawableObject, HitType type) { - hitExplosionContainer.Add(new HitExplosion(drawableObject, type)); + hitExplosionContainer.Add(new HitExplosion(drawableObject)); if (drawableObject.HitObject.Kiai) kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type)); } From df55439f8b15d167491fba706987278f50bd4ac0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Apr 2020 23:24:12 +0900 Subject: [PATCH 15/57] Remove undetected usings --- osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs index ca0c60b67a..3a9779c93b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -8,8 +8,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects.Drawables; From a34ec03efc685c706004fb578da9fddb1f5855d2 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 27 Apr 2020 12:44:20 -0700 Subject: [PATCH 16/57] Reword width comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bartłomiej Dach --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 09f4befbc1..b32875f723 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -272,7 +272,7 @@ namespace osu.Game.Overlays.Mods Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold), Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Width = 70, // to avoid footer from flowing when clicking mods + Width = 70, // to prevent footer from flowing when clicking mods }, }, }, From f387fe310f04cf87f182961e6209477bb6a9394a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 11:07:31 +0900 Subject: [PATCH 17/57] Fix regressing hits test --- .../DrawableTestHit.cs | 29 +++++++++++++++++++ .../Skinning/TestSceneHitExplosion.cs | 21 +------------- .../TestSceneHits.cs | 12 +++----- 3 files changed, 34 insertions(+), 28 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs new file mode 100644 index 0000000000..1db07b3244 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.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 osu.Framework.Allocation; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + internal class DrawableTestHit : DrawableTaikoHitObject + { + private readonly HitResult type; + + public DrawableTestHit(Hit hit, HitResult type = HitResult.Great) + : base(hit) + { + this.type = type; + } + + [BackgroundDependencyLoader] + private void load() + { + Result.Type = type; + } + + public override bool OnPressed(TaikoAction action) => false; + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs index 3a9779c93b..791c438c94 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -53,25 +53,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning }; } - private DrawableTaikoHitObject createHit(HitResult type) => new TestDrawableHit(new Hit { StartTime = Time.Current }, type); - - private class TestDrawableHit : DrawableTaikoHitObject - { - private readonly HitResult type; - - public TestDrawableHit(Hit hit, HitResult type) - : base(hit) - { - this.type = type; - } - - [BackgroundDependencyLoader] - private void load() - { - Result.Type = type; - } - - public override bool OnPressed(TaikoAction action) => false; - } + private DrawableTaikoHitObject createHit(HitResult type) => new DrawableTestHit(new Hit { StartTime = Time.Current }, type); } } diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs index 23adb79083..44452d70c1 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs @@ -149,6 +149,8 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; + Add(h); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult }); } @@ -164,6 +166,8 @@ namespace osu.Game.Rulesets.Taiko.Tests var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) }; + Add(h); + ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult }); ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great }); } @@ -249,13 +253,5 @@ namespace osu.Game.Rulesets.Taiko.Tests public override bool OnPressed(TaikoAction action) => false; } - - private class DrawableTestHit : DrawableHitObject - { - public DrawableTestHit(TaikoHitObject hitObject) - : base(hitObject) - { - } - } } } From 84641765c5858976fc2fa43606e77f60d4f7e7f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 11:08:19 +0900 Subject: [PATCH 18/57] Adjust exceptions and fix capitalisation --- .../Skinning/TaikoLegacySkinTransformer.cs | 7 ++++--- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs index bea1c6bdcf..f0df612e18 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.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 osu.Framework.Audio.Sample; using osu.Framework.Bindables; @@ -86,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning case TaikoSkinComponents.TaikoExplosionGreat: case TaikoSkinComponents.TaikoExplosionMiss: - var sprite = this.GetAnimation(getHitname(taikoComponent.Component), true, false); + var sprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false); if (sprite != null) return new LegacyHitExplosion(sprite); @@ -96,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning return source.GetDrawableComponent(component); } - private string getHitname(TaikoSkinComponents component) + private string getHitName(TaikoSkinComponents component) { switch (component) { @@ -110,7 +111,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning return "taiko-hit300"; } - return string.Empty; + throw new ArgumentOutOfRangeException(nameof(component), "Invalid result type"); } public Texture GetTexture(string componentName) => source.GetTexture(componentName); diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 9bef93d834..35a54d6ea7 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Taiko.UI return TaikoSkinComponents.TaikoExplosionGreat; } - throw new ArgumentException("Invalid result type", nameof(resultType)); + throw new ArgumentOutOfRangeException(nameof(resultType), "Invalid result type"); } protected override void LoadComplete() From 62be138aa912ca3cd77e53d3df39cff877b3f7f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 11:46:08 +0900 Subject: [PATCH 19/57] Avoid calls on MusicController executing before it may have finished loading --- .../TestSceneNowPlayingOverlay.cs | 17 +++++++++-------- osu.Game/Overlays/MusicController.cs | 18 +++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs index 2ea9aec50a..e2913833a7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs @@ -47,18 +47,19 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestPrevTrackBehavior() { - AddStep(@"Play track", () => - { - musicController.NextTrack(); - currentBeatmap = Beatmap.Value; - }); + AddStep(@"Next track", () => musicController.NextTrack()); + AddStep("Store track", () => currentBeatmap = Beatmap.Value); AddStep(@"Seek track to 6 second", () => musicController.SeekTo(6000)); AddUntilStep(@"Wait for current time to update", () => currentBeatmap.Track.CurrentTime > 5000); - AddAssert(@"Check action is restart track", () => musicController.PreviousTrack() == PreviousTrackResult.Restart); - AddUntilStep("Wait for current time to update", () => Precision.AlmostEquals(currentBeatmap.Track.CurrentTime, 0)); + + AddStep(@"Set previous", () => musicController.PreviousTrack()); + AddAssert(@"Check track didn't change", () => currentBeatmap == Beatmap.Value); - AddAssert(@"Check action is not restart", () => musicController.PreviousTrack() != PreviousTrackResult.Restart); + AddUntilStep("Wait for current time to update", () => currentBeatmap.Track.CurrentTime < 5000); + + AddStep(@"Set previous", () => musicController.PreviousTrack()); + AddAssert(@"Check track did change", () => currentBeatmap != Beatmap.Value); } } } diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index d788929739..6d269aa944 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -172,10 +172,15 @@ namespace osu.Game.Overlays } /// - /// Play the previous track or restart the current track if it's current time below + /// Play the previous track or restart the current track if it's current time below . /// - /// The that indicate the decided action - public PreviousTrackResult PreviousTrack() + public void PreviousTrack() => Schedule(() => prev()); + + /// + /// Play the previous track or restart the current track if it's current time below . + /// + /// The that indicate the decided action. + private PreviousTrackResult prev() { var currentTrackPosition = current?.Track.CurrentTime; @@ -204,8 +209,7 @@ namespace osu.Game.Overlays /// /// Play the next random or playlist track. /// - /// Whether the operation was successful. - public bool NextTrack() => next(); + public void NextTrack() => Schedule(() => next()); private bool next(bool instant = false) { @@ -319,13 +323,13 @@ namespace osu.Game.Overlays return true; case GlobalAction.MusicNext: - if (NextTrack()) + if (next()) onScreenDisplay?.Display(new MusicControllerToast("Next track")); return true; case GlobalAction.MusicPrev: - switch (PreviousTrack()) + switch (prev()) { case PreviousTrackResult.Restart: onScreenDisplay?.Display(new MusicControllerToast("Restart track")); From 4fff08d241a2158da662863426e07fa1f1621f8a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 28 Apr 2020 12:19:39 +0900 Subject: [PATCH 20/57] Remove unused using --- .../Visual/UserInterface/TestSceneNowPlayingOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs index e2913833a7..9944e6f9d0 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs @@ -4,7 +4,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Rulesets.Osu; From 81e73acb1a05863fbda05603e3505a8fe5c79931 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 12:14:22 +0900 Subject: [PATCH 21/57] Fix tests failing when not run in certain order --- .../TestSceneNowPlayingOverlay.cs | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs index 9944e6f9d0..a9c52bd189 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.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.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -43,9 +44,29 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep(@"hide", () => nowPlayingOverlay.Hide()); } + [Resolved] + private BeatmapManager manager { get; set; } + [Test] public void TestPrevTrackBehavior() { + // ensure we have at least two beatmaps available. + AddRepeatStep("import beatmap", () => manager.Import(new BeatmapSetInfo + { + Beatmaps = new List + { + new BeatmapInfo + { + BaseDifficulty = new BeatmapDifficulty(), + } + }, + Metadata = new BeatmapMetadata + { + Artist = "a test map", + Title = "title", + } + }).Wait(), 5); + AddStep(@"Next track", () => musicController.NextTrack()); AddStep("Store track", () => currentBeatmap = Beatmap.Value); @@ -54,11 +75,11 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep(@"Set previous", () => musicController.PreviousTrack()); - AddAssert(@"Check track didn't change", () => currentBeatmap == Beatmap.Value); + AddAssert(@"Check beatmap didn't change", () => currentBeatmap == Beatmap.Value); AddUntilStep("Wait for current time to update", () => currentBeatmap.Track.CurrentTime < 5000); AddStep(@"Set previous", () => musicController.PreviousTrack()); - AddAssert(@"Check track did change", () => currentBeatmap != Beatmap.Value); + AddAssert(@"Check beatmap did change", () => currentBeatmap != Beatmap.Value); } } } From 743a92bbbedcd696d7df90bb07dd1bdb049e0b79 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 12:40:56 +0900 Subject: [PATCH 22/57] Use a local database for now playing test --- .../UserInterface/TestSceneNowPlayingOverlay.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs index a9c52bd189..ee922a073a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs @@ -4,9 +4,12 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Overlays; +using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; namespace osu.Game.Tests.Visual.UserInterface @@ -21,9 +24,14 @@ namespace osu.Game.Tests.Visual.UserInterface private NowPlayingOverlay nowPlayingOverlay; + private RulesetStore rulesets; + [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio, GameHost host) { + Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); nowPlayingOverlay = new NowPlayingOverlay @@ -44,9 +52,10 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep(@"hide", () => nowPlayingOverlay.Hide()); } - [Resolved] private BeatmapManager manager { get; set; } + private int importId = 0; + [Test] public void TestPrevTrackBehavior() { @@ -62,7 +71,7 @@ namespace osu.Game.Tests.Visual.UserInterface }, Metadata = new BeatmapMetadata { - Artist = "a test map", + Artist = $"a test map {importId++}", Title = "title", } }).Wait(), 5); From 0d752dc7b847cc162a3076f72c20e487833e724e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 12:55:57 +0900 Subject: [PATCH 23/57] Remove redundant initialisation --- .../Visual/UserInterface/TestSceneNowPlayingOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs index ee922a073a..532744a0fc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.UserInterface private BeatmapManager manager { get; set; } - private int importId = 0; + private int importId; [Test] public void TestPrevTrackBehavior() From 832fa74a5e06146fc7572b841f7d957c9d44afdc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 13:26:42 +0900 Subject: [PATCH 24/57] Reword comment slightly --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index b32875f723..3d0ad1a594 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -272,7 +272,7 @@ namespace osu.Game.Overlays.Mods Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold), Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Width = 70, // to prevent footer from flowing when clicking mods + Width = 70, // make width fixed so reflow doesn't occur when multiplier number changes. }, }, }, From 7342e0015161a7b7e339370ac4aa6aadcee6f3ce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 14:00:14 +0900 Subject: [PATCH 25/57] Convert positions to local HOC coordinate space --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 8d012c63ac..b415c9f0c9 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -46,9 +46,7 @@ namespace osu.Game.Rulesets.Mania.Edit { var hoc = Playfield.GetColumn(0).HitObjectContainer; - position.Y -= ToLocalSpace(hoc.ScreenSpaceDrawQuad.TopLeft).Y; - - float targetPosition = position.Y; + float targetPosition = hoc.ToLocalSpace(ToScreenSpace(position)).Y; if (drawableRuleset.ScrollingInfo.Direction.Value == ScrollingDirection.Down) { From da30eafa3020d3c1479e32ca4e37f43e114098ad Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 14:47:45 +0900 Subject: [PATCH 26/57] Prevent potential exception --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 5062c92afe..7170d425e2 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.UI /// public PassThroughInputManager KeyBindingInputManager; - public override double GameplayStartTime => Objects.First().StartTime - 2000; + public override double GameplayStartTime => Objects.FirstOrDefault()?.StartTime - 2000 ?? 0; private readonly Lazy playfield; From d905ef53b37ac287c2072fb8bcb26c8704211c27 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 14:47:52 +0900 Subject: [PATCH 27/57] Add test scene for mania composer --- .../TestSceneManiaHitObjectComposer.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs new file mode 100644 index 0000000000..3cd2530f36 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.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 System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Edit; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Screens.Edit; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests +{ + public class TestSceneManiaHitObjectComposer : EditorClockTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ManiaBlueprintContainer) + }; + + [Cached(typeof(EditorBeatmap))] + [Cached(typeof(IBeatSnapProvider))] + private readonly EditorBeatmap editorBeatmap; + + protected override Container Content { get; } + + private ManiaHitObjectComposer composer; + + public TestSceneManiaHitObjectComposer() + { + base.Content.Add(new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })) + { + BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo } + }, + Content = new Container + { + RelativeSizeAxes = Axes.Both, + } + }, + }); + + for (int i = 0; i < 10; i++) + { + editorBeatmap.Add(new Note { StartTime = 100 * i }); + } + } + + [SetUp] + public void Setup() => Schedule(() => + { + Children = new Drawable[] + { + composer = new ManiaHitObjectComposer(new ManiaRuleset()) + }; + + BeatDivisor.Value = 8; + }); + } +} From 330521a2ae7f268b1645c03fc7feab010c48ce74 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 15:34:10 +0900 Subject: [PATCH 28/57] Fix lifetime override not working --- .../Drawables/DrawableManiaHitObject.cs | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 88888001b4..a44d8b09aa 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -13,11 +13,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { public abstract class DrawableManiaHitObject : DrawableHitObject { - /// - /// Whether this should always remain alive. - /// - internal bool AlwaysAlive; - /// /// The which causes this to be hit. /// @@ -54,7 +49,62 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Direction.BindValueChanged(OnDirectionChanged, true); } - protected override bool ShouldBeAlive => AlwaysAlive || base.ShouldBeAlive; + private double computedLifetimeStart; + + public override double LifetimeStart + { + get => base.LifetimeStart; + set + { + computedLifetimeStart = value; + + if (!AlwaysAlive) + base.LifetimeStart = value; + } + } + + private double computedLifetimeEnd; + + public override double LifetimeEnd + { + get => base.LifetimeEnd; + set + { + computedLifetimeEnd = value; + + if (!AlwaysAlive) + base.LifetimeEnd = value; + } + } + + private bool alwaysAlive; + + /// + /// Whether this should always remain alive. + /// + internal bool AlwaysAlive + { + get => alwaysAlive; + set + { + if (alwaysAlive == value) + return; + + alwaysAlive = value; + + if (value) + { + // Set the base lifetimes directly, to avoid mangling the computed lifetimes + base.LifetimeStart = double.MinValue; + base.LifetimeEnd = double.MaxValue; + } + else + { + LifetimeStart = computedLifetimeStart; + LifetimeEnd = computedLifetimeEnd; + } + } + } protected virtual void OnDirectionChanged(ValueChangedEvent e) { From 3eb7c8755c1ed9e21a36ab0cee16047aab20f6e1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 15:34:41 +0900 Subject: [PATCH 29/57] Cleanup --- .../TestSceneManiaHitObjectComposer.cs | 4 +-- .../Blueprints/ManiaSelectionBlueprint.cs | 29 ------------------- .../Edit/ManiaSelectionHandler.cs | 11 ------- 3 files changed, 1 insertion(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs index 3cd2530f36..180ceb94f4 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs @@ -29,8 +29,6 @@ namespace osu.Game.Rulesets.Mania.Tests protected override Container Content { get; } - private ManiaHitObjectComposer composer; - public TestSceneManiaHitObjectComposer() { base.Content.Add(new Container @@ -60,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.Tests { Children = new Drawable[] { - composer = new ManiaHitObjectComposer(new ManiaRuleset()) + new ManiaHitObjectComposer(new ManiaRuleset()) }; BeatDivisor.Value = 8; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs index 14d52dd08e..b03bf7c078 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -3,8 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Input.Events; -using osu.Framework.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; @@ -15,13 +13,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints { public class ManiaSelectionBlueprint : OverlaySelectionBlueprint { - public Vector2 ScreenSpaceDragPosition { get; private set; } - public Vector2 DragPosition { get; private set; } - public new DrawableManiaHitObject DrawableObject => (DrawableManiaHitObject)base.DrawableObject; - protected IClock EditorClock { get; private set; } - [Resolved] private IScrollingInfo scrollingInfo { get; set; } @@ -34,12 +27,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints RelativeSizeAxes = Axes.None; } - [BackgroundDependencyLoader] - private void load(IAdjustableClock clock) - { - EditorClock = clock; - } - protected override void Update() { base.Update(); @@ -47,22 +34,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints Position = Parent.ToLocalSpace(DrawableObject.ToScreenSpace(Vector2.Zero)); } - protected override bool OnMouseDown(MouseDownEvent e) - { - ScreenSpaceDragPosition = e.ScreenSpaceMousePosition; - DragPosition = DrawableObject.ToLocalSpace(e.ScreenSpaceMousePosition); - - return base.OnMouseDown(e); - } - - protected override void OnDrag(DragEvent e) - { - base.OnDrag(e); - - ScreenSpaceDragPosition = e.ScreenSpaceMousePosition; - DragPosition = DrawableObject.ToLocalSpace(e.ScreenSpaceMousePosition); - } - public override void Show() { DrawableObject.AlwaysAlive = true; diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 989e0f5b01..11e9b56a53 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -4,11 +4,9 @@ using System; 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; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Screens.Edit.Compose.Components; @@ -22,14 +20,6 @@ namespace osu.Game.Rulesets.Mania.Edit [Resolved] private IManiaHitObjectComposer composer { get; set; } - private IClock editorClock; - - [BackgroundDependencyLoader] - private void load(IAdjustableClock clock) - { - editorClock = clock; - } - public override bool HandleMovement(MoveSelectionEvent moveEvent) { var maniaBlueprint = (ManiaSelectionBlueprint)moveEvent.Blueprint; @@ -50,7 +40,6 @@ namespace osu.Game.Rulesets.Mania.Edit var b = (OverlaySelectionBlueprint)selectionBlueprint; var hitObject = b.DrawableObject; - var objectParent = (HitObjectContainer)hitObject.Parent; // We receive multiple movement events per frame such that we can't rely on updating the start time // since the scrolling hitobject container requires at least one update frame to update the position. From 31c3fd86b9ffc1117cff3628a4441309255c504b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 16:22:00 +0900 Subject: [PATCH 30/57] Avoid using internal EF methods in tests --- osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs index 2d4587341d..b7b48ec06a 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs @@ -1,9 +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; using System.Collections.Generic; using System.Linq; -using Microsoft.EntityFrameworkCore.Internal; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Rulesets.Objects; @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Beatmaps 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)); + Assert.That(Array.IndexOf(editorBeatmap.HitObjects.ToArray(), hitCircle), Is.EqualTo(3)); } /// @@ -161,7 +161,7 @@ namespace osu.Game.Tests.Beatmaps hitCircle.StartTime = 0; Assert.That(editorBeatmap.HitObjects.Count(h => h == hitCircle), Is.EqualTo(1)); - Assert.That(editorBeatmap.HitObjects.IndexOf(hitCircle), Is.EqualTo(1)); + Assert.That(Array.IndexOf(editorBeatmap.HitObjects.ToArray(), hitCircle), Is.EqualTo(1)); } /// From f3fbb3cdc6595bda5e66382b01027bcdf4498ce1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 16:49:43 +0900 Subject: [PATCH 31/57] Add to banned symbols --- CodeAnalysis/BannedSymbols.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CodeAnalysis/BannedSymbols.txt b/CodeAnalysis/BannedSymbols.txt index a92191a439..4d7135a195 100644 --- a/CodeAnalysis/BannedSymbols.txt +++ b/CodeAnalysis/BannedSymbols.txt @@ -4,3 +4,4 @@ M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals( M:System.Nullable`1.Equals(System.Object)~System.Boolean;Use == instead. T:System.IComparable;Don't use non-generic IComparable. Use generic version instead. M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText. +T:Microsoft.EntityFrameworkCore.Internal.EnumerableExtensions;Don't use internal extension methods. \ No newline at end of file From c3a41c8476d97a5710e90b6da19e72787b026449 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 16:56:36 +0900 Subject: [PATCH 32/57] Also avoid using internal TypeExtensions --- CodeAnalysis/BannedSymbols.txt | 3 ++- osu.Game/Screens/OsuScreen.cs | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CodeAnalysis/BannedSymbols.txt b/CodeAnalysis/BannedSymbols.txt index 4d7135a195..e34626a59e 100644 --- a/CodeAnalysis/BannedSymbols.txt +++ b/CodeAnalysis/BannedSymbols.txt @@ -4,4 +4,5 @@ M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals( M:System.Nullable`1.Equals(System.Object)~System.Boolean;Use == instead. T:System.IComparable;Don't use non-generic IComparable. Use generic version instead. M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText. -T:Microsoft.EntityFrameworkCore.Internal.EnumerableExtensions;Don't use internal extension methods. \ No newline at end of file +T:Microsoft.EntityFrameworkCore.Internal.EnumerableExtensions;Don't use internal extension methods. +T:Microsoft.EntityFrameworkCore.Internal.TypeExtensions;Don't use internal extension methods. diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 61e94ae969..2124a66a75 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Internal; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -31,7 +30,7 @@ namespace osu.Game.Screens /// /// A user-facing title for this screen. /// - public virtual string Title => GetType().ShortDisplayName(); + public virtual string Title => GetType().Name; public string Description => Title; From e5131400e77d7ba9c213259ad883fc715206b9f7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 18:34:39 +0900 Subject: [PATCH 33/57] Remove now unnecessary position manipulation --- .../Edit/ManiaSelectionHandler.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 11e9b56a53..55245198c8 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using osu.Framework.Allocation; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.UI.Scrolling; @@ -25,29 +24,11 @@ namespace osu.Game.Rulesets.Mania.Edit var maniaBlueprint = (ManiaSelectionBlueprint)moveEvent.Blueprint; int lastColumn = maniaBlueprint.DrawableObject.HitObject.Column; - performDragMovement(moveEvent); performColumnMovement(lastColumn, moveEvent); return true; } - private void performDragMovement(MoveSelectionEvent moveEvent) - { - float delta = moveEvent.InstantDelta.Y; - - foreach (var selectionBlueprint in SelectedBlueprints) - { - var b = (OverlaySelectionBlueprint)selectionBlueprint; - - var hitObject = b.DrawableObject; - - // We receive multiple movement events per frame such that we can't rely on updating the start time - // since the scrolling hitobject container requires at least one update frame to update the position. - // However the position needs to be valid for future movement events to calculate the correct deltas. - hitObject.Y += delta; - } - } - private void performColumnMovement(int lastColumn, MoveSelectionEvent moveEvent) { var currentColumn = composer.ColumnAt(moveEvent.ScreenSpacePosition); From a7a680b4862e5adf6d0579b81534f07b169488c4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 18:34:55 +0900 Subject: [PATCH 34/57] Fix horizontal drag not working --- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index f9faa262ed..6960d15f31 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI { foreach (var column in stage.Columns) { - if (column.ReceivePositionalInputAt(screenSpacePosition)) + if (column.ReceivePositionalInputAt(new Vector2(screenSpacePosition.X, column.ScreenSpaceDrawQuad.Centre.Y))) { found = column; break; From f93291e25b4967edd658d3e309d33905684d5343 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 18:35:22 +0900 Subject: [PATCH 35/57] Remove unused override --- .../Blueprints/ManiaSelectionBlueprint.cs | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs index b03bf7c078..b8574b804e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -45,25 +45,5 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints DrawableObject.AlwaysAlive = false; base.Hide(); } - - public override Vector2 GetInstantDelta(Vector2 screenSpacePosition) - { - var baseDelta = base.GetInstantDelta(screenSpacePosition); - - if (scrollingInfo.Direction.Value == ScrollingDirection.Down) - { - // The parent of DrawableObject is the scrolling hitobject container (SHOC). - // In the coordinate-space of the SHOC, the screen-space position at the hit target is equal to the height of the SHOC, - // but this is not what we want as it means a slight movement downwards results in a delta greater than the height of the SHOC. - // To get around this issue, the height of the SHOC is subtracted from the delta. - // - // Ideally this should be a _negative_ value in the case described above, however this code gives a _positive_ delta. - // This is intentional as the delta is added to the hitobject's position (see: ManiaSelectionHandler) and a negative delta would move them towards the top of the screen instead, - // which would cause the delta to get increasingly larger as additional movements are performed. - return new Vector2(baseDelta.X, baseDelta.Y - DrawableObject.Parent.DrawHeight); - } - - return baseDelta; - } } } From 7d54d4b800234bb017602dc49e8b2c4a5134193e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 18:35:37 +0900 Subject: [PATCH 36/57] Improve test scene --- .../TestSceneManiaHitObjectComposer.cs | 171 ++++++++++++++---- .../Edit/ManiaHitObjectComposer.cs | 2 + osu.Game/Tests/Visual/EditorClockTestScene.cs | 2 +- 3 files changed, 140 insertions(+), 35 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs index 180ceb94f4..4ce2424ffa 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs @@ -3,16 +3,23 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Edit; using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Screens.Edit; using osu.Game.Tests.Visual; +using osuTK; +using osuTK.Input; namespace osu.Game.Rulesets.Mania.Tests { @@ -23,45 +30,141 @@ namespace osu.Game.Rulesets.Mania.Tests typeof(ManiaBlueprintContainer) }; - [Cached(typeof(EditorBeatmap))] - [Cached(typeof(IBeatSnapProvider))] - private readonly EditorBeatmap editorBeatmap; - - protected override Container Content { get; } - - public TestSceneManiaHitObjectComposer() - { - base.Content.Add(new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })) - { - BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo } - }, - Content = new Container - { - RelativeSizeAxes = Axes.Both, - } - }, - }); - - for (int i = 0; i < 10; i++) - { - editorBeatmap.Add(new Note { StartTime = 100 * i }); - } - } + private TestComposer composer; [SetUp] public void Setup() => Schedule(() => { - Children = new Drawable[] - { - new ManiaHitObjectComposer(new ManiaRuleset()) - }; - BeatDivisor.Value = 8; + Clock.Seek(0); + + Child = composer = new TestComposer { RelativeSizeAxes = Axes.Both }; }); + + [Test] + public void TestDragOffscreenSelectionVerticallyUpScroll() + { + DrawableHitObject lastObject = null; + Vector2 originalPosition = Vector2.Zero; + + AddStep("seek to last object", () => + { + lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last()); + Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); + }); + + AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects)); + + AddStep("click last object", () => + { + originalPosition = lastObject.DrawPosition; + + InputManager.MoveMouseTo(lastObject); + InputManager.PressButton(MouseButton.Left); + }); + + AddStep("move mouse downwards", () => + { + InputManager.MoveMouseTo(lastObject, new Vector2(0, 20)); + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddAssert("hitobjects not moved columns", () => composer.EditorBeatmap.HitObjects.All(h => ((ManiaHitObject)h).Column == 0)); + AddAssert("hitobjects moved downwards", () => lastObject.DrawPosition.Y - originalPosition.Y > 0); + AddAssert("hitobjects not moved too far", () => lastObject.DrawPosition.Y - originalPosition.Y < 50); + } + + [Test] + public void TestDragOffscreenSelectionVerticallyDownScroll() + { + DrawableHitObject lastObject = null; + Vector2 originalPosition = Vector2.Zero; + + AddStep("set down scroll", () => ((Bindable)composer.Composer.ScrollingInfo.Direction).Value = ScrollingDirection.Down); + + AddStep("seek to last object", () => + { + lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last()); + Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); + }); + + AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects)); + + AddStep("click last object", () => + { + originalPosition = lastObject.DrawPosition; + + InputManager.MoveMouseTo(lastObject); + InputManager.PressButton(MouseButton.Left); + }); + + AddStep("move mouse upwards", () => + { + InputManager.MoveMouseTo(lastObject, new Vector2(0, -20)); + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddAssert("hitobjects not moved columns", () => composer.EditorBeatmap.HitObjects.All(h => ((ManiaHitObject)h).Column == 0)); + AddAssert("hitobjects moved upwards", () => originalPosition.Y - lastObject.DrawPosition.Y > 0); + AddAssert("hitobjects not moved too far", () => originalPosition.Y - lastObject.DrawPosition.Y < 50); + } + + [Test] + public void TestDragOffscreenSelectionHorizontally() + { + DrawableHitObject lastObject = null; + Vector2 originalPosition = Vector2.Zero; + + AddStep("seek to last object", () => + { + lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last()); + originalPosition = lastObject.DrawPosition; + + Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); + }); + + AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects)); + + AddStep("click last object", () => + { + InputManager.MoveMouseTo(lastObject); + InputManager.PressButton(MouseButton.Left); + }); + + AddStep("move mouse right", () => + { + InputManager.MoveMouseTo(lastObject, new Vector2(40, 0)); + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddAssert("hitobjects moved columns", () => composer.EditorBeatmap.HitObjects.All(h => ((ManiaHitObject)h).Column == 1)); + + // Todo: They'll have moved vertically by half the height of a note. Probably a problem. + AddAssert("hitobjects not moved vertically", () => lastObject.DrawPosition.Y - originalPosition.Y < 10); + } + + private class TestComposer : CompositeDrawable + { + [Cached(typeof(EditorBeatmap))] + [Cached(typeof(IBeatSnapProvider))] + public readonly EditorBeatmap EditorBeatmap; + + public readonly ManiaHitObjectComposer Composer; + + public TestComposer() + { + InternalChildren = new Drawable[] + { + EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })) + { + BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo } + }, + Composer = new ManiaHitObjectComposer(new ManiaRuleset()) + }; + + for (int i = 0; i < 10; i++) + EditorBeatmap.Add(new Note { StartTime = 100 * i }); + } + } } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index b415c9f0c9..fba80f92d2 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Mania.Edit public ManiaPlayfield Playfield => ((ManiaPlayfield)drawableRuleset.Playfield); + public IScrollingInfo ScrollingInfo => drawableRuleset.ScrollingInfo; + public int TotalColumns => Playfield.TotalColumns; public override (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time) diff --git a/osu.Game/Tests/Visual/EditorClockTestScene.cs b/osu.Game/Tests/Visual/EditorClockTestScene.cs index 58a443ed3d..830e6ed363 100644 --- a/osu.Game/Tests/Visual/EditorClockTestScene.cs +++ b/osu.Game/Tests/Visual/EditorClockTestScene.cs @@ -15,7 +15,7 @@ namespace osu.Game.Tests.Visual /// Provides a clock, beat-divisor, and scrolling capability for test cases of editor components that /// are preferrably tested within the presence of a clock and seek controls. /// - public abstract class EditorClockTestScene : OsuTestScene + public abstract class EditorClockTestScene : OsuManualInputManagerTestScene { protected readonly BindableBeatDivisor BeatDivisor = new BindableBeatDivisor(); protected new readonly EditorClock Clock; From ff24a15760167b1db112239b6c3418870654f5a1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 18:36:24 +0900 Subject: [PATCH 37/57] Fix vertical drag in down-scroll scenarios --- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index fba80f92d2..af465af16a 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -52,9 +52,9 @@ namespace osu.Game.Rulesets.Mania.Edit if (drawableRuleset.ScrollingInfo.Direction.Value == ScrollingDirection.Down) { - // When scrolling downwards, the position is _negative_ when the object's start time is after the current time (e.g. in the middle of the stage). - // However all scrolling algorithms upwards scrolling, meaning that a positive (inverse) position is expected in the same scenario. - targetPosition = -targetPosition; + // We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. + // The scrolling algorithm assumes a top anchor meaning an increase in time corresponds to an increase in position, so when scrolling downwards the coordinates need to be flipped. + targetPosition = hoc.DrawHeight - targetPosition; } double targetTime = drawableRuleset.ScrollingInfo.Algorithm.TimeAt(targetPosition, From db12fafc2c3187220488e6235acc4f93cfa97687 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 18:53:30 +0900 Subject: [PATCH 38/57] Update comment --- .../TestSceneManiaHitObjectComposer.cs | 5 +++-- osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs index 4ce2424ffa..a84fe83245 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Edit; using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Screens.Edit; @@ -139,8 +140,8 @@ namespace osu.Game.Rulesets.Mania.Tests AddAssert("hitobjects moved columns", () => composer.EditorBeatmap.HitObjects.All(h => ((ManiaHitObject)h).Column == 1)); - // Todo: They'll have moved vertically by half the height of a note. Probably a problem. - AddAssert("hitobjects not moved vertically", () => lastObject.DrawPosition.Y - originalPosition.Y < 10); + // Todo: They'll move vertically by the height of a note since there's no snapping and the selection point is the middle of the note. + AddAssert("hitobjects not moved vertically", () => lastObject.DrawPosition.Y - originalPosition.Y <= DefaultNotePiece.NOTE_HEIGHT); } private class TestComposer : CompositeDrawable diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index af465af16a..dfa933baad 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -53,7 +53,8 @@ namespace osu.Game.Rulesets.Mania.Edit if (drawableRuleset.ScrollingInfo.Direction.Value == ScrollingDirection.Down) { // We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. - // The scrolling algorithm assumes a top anchor meaning an increase in time corresponds to an increase in position, so when scrolling downwards the coordinates need to be flipped. + // The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position, + // so when scrolling downwards the coordinates need to be flipped. targetPosition = hoc.DrawHeight - targetPosition; } From ff3928465c06a7e578afe1088a9b0a045ea2eca7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 18:55:58 +0900 Subject: [PATCH 39/57] Add xmldoc --- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 6960d15f31..1af7d06998 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -87,8 +87,17 @@ namespace osu.Game.Rulesets.Mania.UI return found; } + /// + /// Retrieves a by index. + /// + /// The index of the column. + /// The corresponding to the given index. + /// If is less than 0 or greater than . public Column GetColumn(int index) { + if (index < 0 || index > TotalColumns - 1) + throw new ArgumentOutOfRangeException(nameof(index)); + foreach (var stage in stages) { if (index >= stage.Columns.Count) From 1aaab40228baa33ccb6cadadf07e84805fa48f66 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 19:23:33 +0900 Subject: [PATCH 40/57] Fix mods affecting mania scroll speed --- .../UI/DrawableManiaRuleset.cs | 25 ++++++++++++++++--- osu.Game/Rulesets/UI/DrawableRuleset.cs | 8 +++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 14cad39b04..39f3331fbb 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; @@ -48,6 +50,10 @@ namespace osu.Game.Rulesets.Mania.UI protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; private readonly Bindable configDirection = new Bindable(); + private readonly Bindable configTimeRange = new Bindable(); + + // Stores the current speed adjustment active in gameplay. + private readonly Track speedAdjustmentTrack = new TrackVirtual(1000); public DrawableManiaRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) @@ -58,6 +64,9 @@ namespace osu.Game.Rulesets.Mania.UI [BackgroundDependencyLoader] private void load() { + foreach (var mod in Mods.OfType()) + mod.ApplyToTrack(speedAdjustmentTrack); + bool isForCurrentRuleset = Beatmap.BeatmapInfo.Ruleset.Equals(Ruleset.RulesetInfo); foreach (var p in ControlPoints) @@ -76,7 +85,8 @@ namespace osu.Game.Rulesets.Mania.UI Config.BindWith(ManiaRulesetSetting.ScrollDirection, configDirection); configDirection.BindValueChanged(direction => Direction.Value = (ScrollingDirection)direction.NewValue, true); - Config.BindWith(ManiaRulesetSetting.ScrollTime, TimeRange); + Config.BindWith(ManiaRulesetSetting.ScrollTime, configTimeRange); + configTimeRange.BindValueChanged(_ => updateTimeRange()); } protected override void AdjustScrollSpeed(int amount) @@ -86,10 +96,19 @@ namespace osu.Game.Rulesets.Mania.UI private double relativeTimeRange { - get => MAX_TIME_RANGE / TimeRange.Value; - set => TimeRange.Value = MAX_TIME_RANGE / value; + get => MAX_TIME_RANGE / configTimeRange.Value; + set => configTimeRange.Value = MAX_TIME_RANGE / value; } + protected override void Update() + { + base.Update(); + + updateTimeRange(); + } + + private void updateTimeRange() => TimeRange.Value = configTimeRange.Value * speedAdjustmentTrack.AggregateTempo.Value * speedAdjustmentTrack.AggregateFrequency.Value; + /// /// Retrieves the column that intersects a screen-space position. /// diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 5062c92afe..0a1c35c7c6 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.UI /// The mods which are to be applied. /// [Cached(typeof(IReadOnlyList))] - private readonly IReadOnlyList mods; + protected readonly IReadOnlyList Mods; private FrameStabilityContainer frameStabilityContainer; @@ -129,7 +129,7 @@ namespace osu.Game.Rulesets.UI throw new ArgumentException($"{GetType()} expected the beatmap to contain hitobjects of type {typeof(TObject)}.", nameof(beatmap)); Beatmap = tBeatmap; - this.mods = mods?.ToArray() ?? Array.Empty(); + Mods = mods?.ToArray() ?? Array.Empty(); RelativeSizeAxes = Axes.Both; @@ -204,7 +204,7 @@ namespace osu.Game.Rulesets.UI .WithChild(ResumeOverlay))); } - applyRulesetMods(mods, config); + applyRulesetMods(Mods, config); loadObjects(cancellationToken); } @@ -224,7 +224,7 @@ namespace osu.Game.Rulesets.UI Playfield.PostProcess(); - foreach (var mod in mods.OfType()) + foreach (var mod in Mods.OfType()) mod.ApplyToDrawableHitObjects(Playfield.AllHitObjects); } From 7868c0dad5cff824fe5bf7c90c0a8d4dea71d5eb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Apr 2020 20:15:56 +0900 Subject: [PATCH 41/57] Fix test case failures --- .../TestSceneManiaHitObjectComposer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs index a84fe83245..286e3f6e50 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectComposer.cs @@ -119,8 +119,6 @@ namespace osu.Game.Rulesets.Mania.Tests AddStep("seek to last object", () => { lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last()); - originalPosition = lastObject.DrawPosition; - Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); }); @@ -128,13 +126,18 @@ namespace osu.Game.Rulesets.Mania.Tests AddStep("click last object", () => { + originalPosition = lastObject.DrawPosition; + InputManager.MoveMouseTo(lastObject); InputManager.PressButton(MouseButton.Left); }); AddStep("move mouse right", () => { - InputManager.MoveMouseTo(lastObject, new Vector2(40, 0)); + var firstColumn = composer.Composer.Playfield.GetColumn(0); + var secondColumn = composer.Composer.Playfield.GetColumn(1); + + InputManager.MoveMouseTo(lastObject, new Vector2(secondColumn.ScreenSpaceDrawQuad.Centre.X - firstColumn.ScreenSpaceDrawQuad.Centre.X + 1, 0)); InputManager.ReleaseButton(MouseButton.Left); }); From 119000f1ab2157762863743d25d111b936f6a4a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Apr 2020 21:43:35 +0900 Subject: [PATCH 42/57] Reduce database includes where possible --- osu.Game/Beatmaps/BeatmapManager.cs | 54 ++++++++++++++++++++-- osu.Game/Beatmaps/BeatmapStore.cs | 12 +++++ osu.Game/Overlays/MusicController.cs | 2 +- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 6 files changed, 67 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 6542866936..5651d07566 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -246,6 +246,12 @@ namespace osu.Game.Beatmaps if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; + if (beatmapInfo.BeatmapSet.Files == null) + { + var info = beatmapInfo; + beatmapInfo = QueryBeatmap(b => b.ID == info.ID); + } + lock (workingCache) { var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID); @@ -287,13 +293,34 @@ namespace osu.Game.Beatmaps /// Returns a list of all usable s. /// /// A list of available . - public List GetAllUsableBeatmapSets() => GetAllUsableBeatmapSetsEnumerable().ToList(); + public List GetAllUsableBeatmapSets(IncludedDetails includes = IncludedDetails.All) => GetAllUsableBeatmapSetsEnumerable(includes).ToList(); /// - /// Returns a list of all usable s. + /// Returns a list of all usable s. Note that files are not populated. /// + /// The level of detail to include in the returned objects. /// A list of available . - public IQueryable GetAllUsableBeatmapSetsEnumerable() => beatmaps.ConsumableItems.Where(s => !s.DeletePending && !s.Protected); + public IQueryable GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes) + { + IQueryable queryable; + + switch (includes) + { + case IncludedDetails.Minimal: + queryable = beatmaps.BeatmapSetsOverview; + break; + + case IncludedDetails.AllButFiles: + queryable = beatmaps.BeatmapSetsWithoutFiles; + break; + + default: + queryable = beatmaps.ConsumableItems; + break; + } + + return queryable.Where(s => !s.DeletePending && !s.Protected); + } /// /// Perform a lookup query on available s. @@ -482,4 +509,25 @@ namespace osu.Game.Beatmaps } } } + + /// + /// The level of detail to include in database results. + /// + public enum IncludedDetails + { + /// + /// Only include beatmap difficulties and set level metadata. + /// + Minimal, + + /// + /// Include all difficulties, rulesets, difficulty metadata but no files. + /// + AllButFiles, + + /// + /// Include everything. + /// + All + } } diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index a2279fdb14..642bafd2ac 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -87,6 +87,18 @@ namespace osu.Game.Beatmaps base.Purge(items, context); } + public IQueryable BeatmapSetsOverview => ContextFactory.Get().BeatmapSetInfo + .Include(s => s.Metadata) + .Include(s => s.Beatmaps) + .AsNoTracking(); + + public IQueryable BeatmapSetsWithoutFiles => ContextFactory.Get().BeatmapSetInfo + .Include(s => s.Metadata) + .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) + .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) + .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) + .AsNoTracking(); + public IQueryable Beatmaps => ContextFactory.Get().BeatmapInfo .Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 6d269aa944..c872f82b32 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays beatmaps.ItemAdded += handleBeatmapAdded; beatmaps.ItemRemoved += handleBeatmapRemoved; - beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next())); + beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets(IncludedDetails.Minimal).OrderBy(_ => RNG.Next())); } protected override void LoadComplete() diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 26455b1dbd..d2296573a6 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Menu if (!MenuMusic.Value) { - var sets = beatmaps.GetAllUsableBeatmapSets(); + var sets = beatmaps.GetAllUsableBeatmapSets(IncludedDetails.Minimal); if (sets.Count > 0) setInfo = beatmaps.QueryBeatmapSet(s => s.ID == sets[RNG.Next(0, sets.Count - 1)].ID); } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index f989ab2787..5a4a03662a 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -169,7 +169,7 @@ namespace osu.Game.Screens.Select loadBeatmapSets(GetLoadableBeatmaps()); } - protected virtual IEnumerable GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable(); + protected virtual IEnumerable GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.AllButFiles); public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() => { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0d07a335cf..c07465ca44 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -286,7 +286,7 @@ namespace osu.Game.Screens.Select Schedule(() => { // if we have no beatmaps but osu-stable is found, let's prompt the user to import. - if (!beatmaps.GetAllUsableBeatmapSetsEnumerable().Any() && beatmaps.StableInstallationAvailable) + if (!beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.Minimal).Any() && beatmaps.StableInstallationAvailable) { dialogOverlay.Push(new ImportFromStablePopup(() => { From 024f10a494f124e632652cae331bbcce1dbf3c39 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 29 Apr 2020 13:24:31 +0900 Subject: [PATCH 43/57] Use non-generic bindable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bartłomiej Dach --- osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 39f3331fbb..fa26e6d713 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Mania.UI protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; private readonly Bindable configDirection = new Bindable(); - private readonly Bindable configTimeRange = new Bindable(); + private readonly Bindable configTimeRange = new BindableDouble(); // Stores the current speed adjustment active in gameplay. private readonly Track speedAdjustmentTrack = new TrackVirtual(1000); From 0c95d11fdb0db19fc1610774961ffe376241d3e5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Apr 2020 13:27:33 +0900 Subject: [PATCH 44/57] Remove unnecessary value change binding --- osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index fa26e6d713..00fa68d088 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -86,7 +86,6 @@ namespace osu.Game.Rulesets.Mania.UI configDirection.BindValueChanged(direction => Direction.Value = (ScrollingDirection)direction.NewValue, true); Config.BindWith(ManiaRulesetSetting.ScrollTime, configTimeRange); - configTimeRange.BindValueChanged(_ => updateTimeRange()); } protected override void AdjustScrollSpeed(int amount) From 4f332ace1426b1c6840d0b4af3aad2e4a8e58e14 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Apr 2020 14:27:21 +0900 Subject: [PATCH 45/57] Use 0 length --- osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 00fa68d088..f3f843f366 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.UI private readonly Bindable configTimeRange = new BindableDouble(); // Stores the current speed adjustment active in gameplay. - private readonly Track speedAdjustmentTrack = new TrackVirtual(1000); + private readonly Track speedAdjustmentTrack = new TrackVirtual(0); public DrawableManiaRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) From c73d45bc01de6d2d2175c028400bb4c6d727c2f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Apr 2020 15:23:28 +0900 Subject: [PATCH 46/57] Reduce initial channel load overhead by only loading history on active channel --- osu.Game/Online/Chat/ChannelManager.cs | 12 ++++++------ osu.Game/Overlays/Chat/DrawableChannel.cs | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 822f628dd2..53872ddcba 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -93,6 +93,12 @@ namespace osu.Game.Online.Chat { if (!(e.NewValue is ChannelSelectorTabItem.ChannelSelectorTabChannel)) JoinChannel(e.NewValue); + + if (e.NewValue?.MessagesLoaded == false) + { + // let's fetch a small number of messages to bring us up-to-date with the backlog. + fetchInitalMessages(e.NewValue); + } } /// @@ -375,12 +381,6 @@ namespace osu.Game.Online.Chat if (CurrentChannel.Value == null) CurrentChannel.Value = channel; - if (!channel.MessagesLoaded) - { - // let's fetch a small number of messages to bring us up-to-date with the backlog. - fetchInitalMessages(channel); - } - return channel; } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 6019657cf0..d63faebae4 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -105,6 +105,14 @@ namespace osu.Game.Overlays.Chat private void newMessagesArrived(IEnumerable newMessages) { + if (newMessages.Min(m => m.Id) < chatLines.Max(c => c.Message.Id)) + { + // there is a case (on initial population) that we may receive past messages and need to reorder. + // easiest way is to just combine messages and recreate drawables (less worrying about day separators etc.) + newMessages = newMessages.Concat(chatLines.Select(c => c.Message)).OrderBy(m => m.Id).ToList(); + ChatLineFlow.Clear(); + } + bool shouldScrollToEnd = scroll.IsScrolledToEnd(10) || !chatLines.Any() || newMessages.Any(m => m is LocalMessage); // Add up to last Channel.MAX_HISTORY messages From d1ec99ffd9c790bf57f10a9592bd9e06b7b4df53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Apr 2020 16:51:22 +0900 Subject: [PATCH 47/57] Further improve beatmap carousel load performance by avoiding incorrect query construction --- osu.Game/Beatmaps/BeatmapManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5651d07566..b8dfac0342 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -300,7 +300,7 @@ namespace osu.Game.Beatmaps /// /// The level of detail to include in the returned objects. /// A list of available . - public IQueryable GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes) + public IEnumerable GetAllUsableBeatmapSetsEnumerable(IncludedDetails includes) { IQueryable queryable; @@ -319,7 +319,10 @@ namespace osu.Game.Beatmaps break; } - return queryable.Where(s => !s.DeletePending && !s.Protected); + // AsEnumerable used here to avoid applying the WHERE in sql. When done so, ef core 2.x uses an incorrect ORDER BY + // clause which causes queries to take 5-10x longer. + // TODO: remove if upgrading to EF core 3.x. + return queryable.AsEnumerable().Where(s => !s.DeletePending && !s.Protected); } /// From 48733a7e2f5c4d0d02666950e5d61fe04d435f25 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Apr 2020 17:53:25 +0900 Subject: [PATCH 48/57] Change taiko hit explosion animation to match stable for skins --- .../Skinning/LegacyHitExplosion.cs | 10 ++++++++-- .../UI/DefaultHitExplosion.cs | 3 +++ osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 16 +++++++--------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs index d29b574866..42d4a34b9d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs @@ -22,8 +22,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning { base.LoadComplete(); - this.FadeIn(120); - this.ScaleTo(0.6f).Then().ScaleTo(1, 240, Easing.OutElastic); + const double animation_time = 120; + + this.FadeInFromZero(animation_time).Then().FadeOut(animation_time * 1.5); + + this.ScaleTo(0.6f) + .Then().ScaleTo(1.1f, animation_time * 0.8) + .Then().ScaleTo(0.9f, animation_time * 0.4) + .Then().ScaleTo(1f, animation_time * 0.2); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs index aa444d0494..a0ca5f1c39 100644 --- a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs @@ -49,6 +49,9 @@ namespace osu.Game.Rulesets.Taiko.UI base.LoadComplete(); this.ScaleTo(3f, 1000, Easing.OutQuint); + this.FadeOut(500); + + Expire(true); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 35a54d6ea7..f0585b9c50 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -23,6 +23,12 @@ namespace osu.Game.Rulesets.Taiko.UI [Cached(typeof(DrawableHitObject))] public readonly DrawableHitObject JudgedObject; + private SkinnableDrawable skinnable; + + public override double LifetimeStart => skinnable.Drawable.LifetimeStart; + + public override double LifetimeEnd => skinnable.Drawable.LifetimeEnd; + public HitExplosion(DrawableHitObject judgedObject) { JudgedObject = judgedObject; @@ -39,7 +45,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load() { - Child = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(JudgedObject.Result?.Type ?? HitResult.Great)), _ => new DefaultHitExplosion()); + Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(JudgedObject.Result?.Type ?? HitResult.Great)), _ => new DefaultHitExplosion()); } private TaikoSkinComponents getComponentName(HitResult resultType) @@ -59,14 +65,6 @@ namespace osu.Game.Rulesets.Taiko.UI throw new ArgumentOutOfRangeException(nameof(resultType), "Invalid result type"); } - protected override void LoadComplete() - { - base.LoadComplete(); - - this.FadeOut(500); - Expire(true); - } - /// /// Transforms this hit explosion to visualise a secondary hit. /// From 783dc58ef0f600073ef115f4e4868902f96473ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Apr 2020 09:41:56 +0900 Subject: [PATCH 49/57] Move taiko additive blending locally to avoid applying to legacy skins --- osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs | 2 ++ osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 2 ++ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 3 --- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs index 42d4a34b9d..c44da9ce1e 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs @@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; + + Blending = BlendingParameters.Additive; } protected override void LoadComplete() diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index 3a307bb3bb..067d390894 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -31,6 +31,8 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both; Size = new Vector2(TaikoHitObject.DEFAULT_SIZE, 1); + Blending = BlendingParameters.Additive; + Masking = true; Alpha = 0.25f; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 6a78c0a1fb..5c763cb332 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -68,7 +68,6 @@ namespace osu.Game.Rulesets.Taiko.UI hitExplosionContainer = new Container { RelativeSizeAxes = Axes.Both, - Blending = BlendingParameters.Additive, }, HitTarget = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.HitTarget), _ => new TaikoHitTarget()) { @@ -100,13 +99,11 @@ namespace osu.Game.Rulesets.Taiko.UI Name = "Kiai hit explosions", RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, - Blending = BlendingParameters.Additive }, judgementContainer = new JudgementContainer { Name = "Judgements", RelativeSizeAxes = Axes.Y, - Blending = BlendingParameters.Additive }, } }, From 49a98fde7374055a8b2aa5286b733ec3673f55ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Apr 2020 09:57:14 +0900 Subject: [PATCH 50/57] Move to non-legacy class --- osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs | 2 -- osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs index c44da9ce1e..42d4a34b9d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs @@ -16,8 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; - - Blending = BlendingParameters.Additive; } protected override void LoadComplete() diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs index a0ca5f1c39..9943a58e3e 100644 --- a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Taiko.UI BorderColour = Color4.White; BorderThickness = 1; + Blending = BlendingParameters.Additive; + Alpha = 0.15f; Masking = true; From cf4e79cf38490ecb85f213b154dc7eef3ffb14ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Apr 2020 11:51:06 +0900 Subject: [PATCH 51/57] Show loading spinner when carousel is not ready to be displayed --- .../SongSelect/TestScenePlaySongSelect.cs | 1 + osu.Game/Screens/Select/SongSelect.cs | 33 +++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 39e04ed39a..aed8e19fb2 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -797,6 +797,7 @@ namespace osu.Game.Tests.Visual.SongSelect { AddStep("create song select", () => LoadScreen(songSelect = new TestSongSelect())); AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); + AddUntilStep("wait for carousel loaded", () => songSelect.Carousel.IsAlive); } private void addManyTestMaps() diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index c07465ca44..6b896694ea 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -34,6 +34,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; +using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; namespace osu.Game.Screens.Select @@ -92,6 +93,8 @@ namespace osu.Game.Screens.Select private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeBeatmap; + private Container carouselContainer; + protected BeatmapDetailArea BeatmapDetails { get; private set; } private readonly Bindable decoupledRuleset = new Bindable(); @@ -105,9 +108,22 @@ namespace osu.Game.Screens.Select // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). transferRulesetValue(); + LoadComponentAsync(Carousel = new BeatmapCarousel + { + AllowSelection = false, // delay any selection until our bindables are ready to make a good choice. + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + BleedTop = FilterControl.HEIGHT, + BleedBottom = Footer.HEIGHT, + SelectionChanged = updateSelectedBeatmap, + BeatmapSetsChanged = carouselBeatmapsLoaded, + GetRecommendedBeatmap = (recommender = new DifficultyRecommender()).GetRecommendedBeatmap, + }, c => carouselContainer.Child = c); + AddRangeInternal(new Drawable[] { - recommender = new DifficultyRecommender(), + recommender, new ResetScrollContainer(() => Carousel.ScrollToSelected()) { RelativeSizeAxes = Axes.Y, @@ -139,7 +155,7 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Right = -150 }, }, }, - new Container + carouselContainer = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding @@ -147,18 +163,7 @@ namespace osu.Game.Screens.Select Top = FilterControl.HEIGHT, Bottom = Footer.HEIGHT }, - Child = Carousel = new BeatmapCarousel - { - AllowSelection = false, // delay any selection until our bindables are ready to make a good choice. - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - BleedTop = FilterControl.HEIGHT, - BleedBottom = Footer.HEIGHT, - SelectionChanged = updateSelectedBeatmap, - BeatmapSetsChanged = carouselBeatmapsLoaded, - GetRecommendedBeatmap = recommender.GetRecommendedBeatmap, - }, + Child = new LoadingSpinner(true) { State = { Value = Visibility.Visible } } } }, } From 21c6ac8c43725f8739dcaea3a2b6105e7feab142 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Apr 2020 12:12:28 +0900 Subject: [PATCH 52/57] Allow closing the game during intro --- osu.Game/OsuGame.cs | 5 +---- osu.Game/Screens/Menu/IntroScreen.cs | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f5f7d0cef4..8e62819c95 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -914,10 +914,7 @@ namespace osu.Game if (ScreenStack.CurrentScreen is Loader) return false; - 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; diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index d2296573a6..736202ee52 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -96,8 +96,6 @@ namespace osu.Game.Screens.Menu Track = introBeatmap.Track; } - public override bool OnExiting(IScreen next) => !DidLoadMenu; - public override void OnResuming(IScreen last) { this.FadeIn(300); From 48af4d4eb4fc3ef8abf757ab512211defddee949 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Apr 2020 16:18:15 +0900 Subject: [PATCH 53/57] Fix skinned taiko hit explosions not being removed on rewind --- osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs index 42d4a34b9d..b5ec2e8def 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs @@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning .Then().ScaleTo(1.1f, animation_time * 0.8) .Then().ScaleTo(0.9f, animation_time * 0.4) .Then().ScaleTo(1f, animation_time * 0.2); + + Expire(true); } } } From d0a8c0fa71bfe372a535380d258eb259b7f60dd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Apr 2020 16:42:38 +0900 Subject: [PATCH 54/57] Add kiai support to osu!taiko skinned playfields --- .../Skinning/TestSceneTaikoPlayfield.cs | 18 ++++++ .../TaikoLegacyPlayfieldBackgroundRight.cs | 57 +++++++++++++++++++ .../Skinning/TaikoLegacySkinTransformer.cs | 9 +-- osu.Game/Beatmaps/WorkingBeatmap.cs | 4 +- osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 4 ++ 5 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs index 16b3c036a3..ae5dd1e622 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Taiko.Beatmaps; using osu.Game.Rulesets.Taiko.Skinning; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI.Scrolling; @@ -34,6 +35,18 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning public TestSceneTaikoPlayfield() { + TaikoBeatmap beatmap; + bool kiai = false; + + AddStep("set beatmap", () => + { + Beatmap.Value = CreateWorkingBeatmap(beatmap = new TaikoBeatmap()); + + beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }); + + Beatmap.Value.Track.Start(); + }); + AddStep("Load playfield", () => SetContents(() => new TaikoPlayfield(new ControlPointInfo()) { Anchor = Anchor.CentreLeft, @@ -41,6 +54,11 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning })); AddRepeatStep("change height", () => this.ChildrenOfType().ForEach(p => p.Height = Math.Max(0.2f, (p.Height + 0.2f) % 1f)), 50); + + AddStep("Toggle kiai", () => + { + Beatmap.Value.Beatmap.ControlPointInfo.Add(0, new EffectControlPoint { KiaiMode = (kiai = !kiai) }); + }); } } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs new file mode 100644 index 0000000000..7508c75231 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs @@ -0,0 +1,57 @@ +// 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.Audio.Track; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning +{ + public class TaikoLegacyPlayfieldBackgroundRight : BeatSyncedContainer + { + private Sprite kiai; + + private bool kiaiDisplayed; + + [BackgroundDependencyLoader] + private void load(ISkinSource skin) + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Sprite + { + Texture = skin.GetTexture("taiko-bar-right"), + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, + }, + kiai = new Sprite + { + Texture = skin.GetTexture("taiko-bar-right-glow"), + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, + Alpha = 0, + } + }; + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) + { + base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); + + if (effectPoint.KiaiMode != kiaiDisplayed) + { + kiaiDisplayed = effectPoint.KiaiMode; + + kiai.ClearTransforms(); + kiai.FadeTo(kiaiDisplayed ? 1 : 0, 200); + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs index f0df612e18..5dfc7ec0df 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Game.Audio; using osu.Game.Skinning; -using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning { @@ -60,13 +59,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning case TaikoSkinComponents.PlayfieldBackgroundRight: if (GetTexture("taiko-bar-right") != null) - { - return this.GetAnimation("taiko-bar-right", false, false).With(d => - { - d.RelativeSizeAxes = Axes.Both; - d.Size = Vector2.One; - }); - } + return new TaikoLegacyPlayfieldBackgroundRight(); return null; diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index f30340956a..d2804bdc05 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -197,7 +197,7 @@ namespace osu.Game.Beatmaps public override string ToString() => BeatmapInfo.ToString(); - public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false; + public virtual bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false; public IBeatmap Beatmap { @@ -233,7 +233,7 @@ namespace osu.Game.Beatmaps protected abstract Texture GetBackground(); private readonly RecyclableLazy background; - public bool TrackLoaded => track.IsResultAvailable; + public virtual bool TrackLoaded => track.IsResultAvailable; public Track Track => track.Value; protected abstract Track GetTrack(); private RecyclableLazy track; diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index 8f8afb87d4..cdf9170701 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs @@ -27,6 +27,10 @@ namespace osu.Game.Tests.Beatmaps this.storyboard = storyboard; } + public override bool TrackLoaded => true; + + public override bool BeatmapLoaded => true; + protected override IBeatmap GetBeatmap() => beatmap; protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard(); From 9bec42bc7ee8e59a1e9faebdc9388350259a7212 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Apr 2020 20:03:46 +0900 Subject: [PATCH 55/57] Fix mania crashing on undo/redo --- osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 17eba87076..45a0a5c485 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -84,7 +84,11 @@ namespace osu.Game.Screens.Edit { using (var stream = new MemoryStream(state)) using (var reader = new LineBufferedReader(stream, true)) - return new PassThroughWorkingBeatmap(Decoder.GetDecoder(reader).Decode(reader)).GetPlayableBeatmap(editorBeatmap.BeatmapInfo.Ruleset); + { + var decoded = Decoder.GetDecoder(reader).Decode(reader); + decoded.BeatmapInfo.Ruleset = editorBeatmap.BeatmapInfo.Ruleset; + return new PassThroughWorkingBeatmap(decoded).GetPlayableBeatmap(editorBeatmap.BeatmapInfo.Ruleset); + } } private class PassThroughWorkingBeatmap : WorkingBeatmap From c96bc5c51cdfe0f607ebd9925ab160358fb10a81 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Apr 2020 20:39:41 +0900 Subject: [PATCH 56/57] Fix undo/redo behaving poorly with simultaneous objects --- .../Editing/LegacyEditorBeatmapPatcherTest.cs | 25 +++++++++++++++++++ osu.Game/Screens/Edit/EditorBeatmap.cs | 20 ++++++++++++--- .../Edit/LegacyEditorBeatmapPatcher.cs | 6 +++-- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs b/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs index a3ab677d96..ff17f23d50 100644 --- a/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs +++ b/osu.Game.Tests/Editing/LegacyEditorBeatmapPatcherTest.cs @@ -304,6 +304,31 @@ namespace osu.Game.Tests.Editing runTest(patch); } + [Test] + public void TestChangeHitObjectAtSameTime() + { + current.AddRange(new[] + { + new HitCircle { StartTime = 500, Position = new Vector2(50) }, + new HitCircle { StartTime = 500, Position = new Vector2(100) }, + new HitCircle { StartTime = 500, Position = new Vector2(150) }, + new HitCircle { StartTime = 500, Position = new Vector2(200) }, + }); + + var patch = new OsuBeatmap + { + HitObjects = + { + new HitCircle { StartTime = 500, Position = new Vector2(150) }, + new HitCircle { StartTime = 500, Position = new Vector2(100) }, + new HitCircle { StartTime = 500, Position = new Vector2(50) }, + new HitCircle { StartTime = 500, Position = new Vector2(200) }, + } + }; + + runTest(patch); + } + private void runTest(IBeatmap patch) { // Due to the method of testing, "patch" comes in without having been decoded via a beatmap decoder. diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index a2d2f08ce9..2e8e03bc73 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -136,14 +136,26 @@ namespace osu.Game.Screens.Edit /// The to add. public void Add(HitObject hitObject) { - trackStartTime(hitObject); - // Preserve existing sorting order in the beatmap var insertionIndex = findInsertionIndex(PlayableBeatmap.HitObjects, hitObject.StartTime); - mutableHitObjects.Insert(insertionIndex + 1, hitObject); + Insert(insertionIndex + 1, hitObject); + } + + /// + /// Inserts a into this . + /// + /// + /// It is the invoker's responsibility to make sure that sorting order is maintained. + /// + /// The index to insert the at. + /// The to insert. + public void Insert(int index, HitObject hitObject) + { + trackStartTime(hitObject); + + mutableHitObjects.Insert(index, hitObject); HitObjectAdded?.Invoke(hitObject); - updateHitObject(hitObject, true); } diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 17eba87076..04faba6478 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -63,8 +63,10 @@ namespace osu.Game.Screens.Edit } } - // Make the removal indices are sorted so that iteration order doesn't get messed up post-removal. + // Sort the indices to ensure that removal + insertion indices don't get jumbled up post-removal or post-insertion. + // This isn't strictly required, but the differ makes no guarantees about order. toRemove.Sort(); + toAdd.Sort(); // Apply the changes. for (int i = toRemove.Count - 1; i >= 0; i--) @@ -74,7 +76,7 @@ namespace osu.Game.Screens.Edit { IBeatmap newBeatmap = readBeatmap(newState); foreach (var i in toAdd) - editorBeatmap.Add(newBeatmap.HitObjects[i]); + editorBeatmap.Insert(i, newBeatmap.HitObjects[i]); } } From 000c34dc26ea9d815f0f76c32510f1a0b5f600a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Apr 2020 21:01:53 +0900 Subject: [PATCH 57/57] Move recommender to field construction --- osu.Game/Screens/Select/SongSelect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6b896694ea..a7e27c27ba 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Select protected BeatmapCarousel Carousel { get; private set; } - private DifficultyRecommender recommender; + private readonly DifficultyRecommender recommender = new DifficultyRecommender(); private BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Select BleedBottom = Footer.HEIGHT, SelectionChanged = updateSelectedBeatmap, BeatmapSetsChanged = carouselBeatmapsLoaded, - GetRecommendedBeatmap = (recommender = new DifficultyRecommender()).GetRecommendedBeatmap, + GetRecommendedBeatmap = recommender.GetRecommendedBeatmap, }, c => carouselContainer.Child = c); AddRangeInternal(new Drawable[]