From 596044e19d79ef0e16908426201a7c97eb8e77da Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 19 Jan 2018 17:25:32 +0100 Subject: [PATCH 1/8] show beatmapsets with pending deletion in osu!direct --- osu.Game/Overlays/DirectOverlay.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index d5acb9dc86..efd54bec82 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -298,13 +298,15 @@ namespace osu.Game.Overlays Task.Run(() => { var onlineIds = response.Select(r => r.OnlineBeatmapSetID).ToList(); - var presentOnlineIds = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID)).Select(r => r.OnlineBeatmapSetID).ToList(); - var sets = response.Select(r => r.ToBeatmapSet(rulesets)).Where(b => !presentOnlineIds.Contains(b.OnlineBeatmapSetID)).ToList(); + var presentSets = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID)).ToList(); + + var responseSets = response.Select(r => r.ToBeatmapSet(rulesets)).ToList(); + var finalSets = responseSets.Where(b => !presentSets.Any(s => s.OnlineBeatmapSetID == b.OnlineBeatmapSetID && !s.DeletePending)).ToList(); // may not need scheduling; loads async internally. Schedule(() => { - BeatmapSets = sets; + BeatmapSets = finalSets; recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value); }); }); From 060d80efbe96e7248b0675247b1475f842408bab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Jan 2018 13:05:07 +0900 Subject: [PATCH 2/8] Continue showing progress bar on direct panels when importing Previously the progrress bar would fade out once downloads completed, which felt unintuitive. --- osu.Game/Graphics/UserInterface/ProgressBar.cs | 2 +- osu.Game/Overlays/Direct/DirectPanel.cs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs index 43fab9fead..6021cf08be 100644 --- a/osu.Game/Graphics/UserInterface/ProgressBar.cs +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface public Color4 FillColour { - set { fill.Colour = value; } + set { fill.FadeColour(value, 150, Easing.OutQuint); } } public Color4 BackgroundColour diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 7dd6be8dc6..7e7e8d8665 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -65,11 +65,14 @@ namespace osu.Game.Overlays.Direct Colour = Color4.Black.Opacity(0.3f), }; + private OsuColour colours; + [BackgroundDependencyLoader(permitNulls: true)] private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay) { this.beatmaps = beatmaps; this.beatmapSetOverlay = beatmapSetOverlay; + this.colours = colours; AddInternal(content = new Container { @@ -188,7 +191,7 @@ namespace osu.Game.Overlays.Direct request.Success += data => { progressBar.Current.Value = 1; - progressBar.FadeOut(500); + progressBar.FillColour = colours.Yellow; }; } From 88beee2d1fad2db1c30acc39d8cb6e50a7a9d4f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Jan 2018 13:17:03 +0900 Subject: [PATCH 3/8] Keep downloads active until their associated import operation finishes This avoids race conditions where a second download can potentially be started while the first is still active. --- osu.Game/Beatmaps/BeatmapManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 634b5bcd20..e6ddf4bfd9 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -287,9 +287,8 @@ namespace osu.Game.Beatmaps Import(archive); downloadNotification.State = ProgressNotificationState.Completed; + currentDownloads.Remove(request); }, TaskCreationOptions.LongRunning); - - currentDownloads.Remove(request); }; request.Failure += data => From 53e40a77dcb3870d74dd616ce4c29a33ada29106 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Jan 2018 13:25:49 +0900 Subject: [PATCH 4/8] Don't show error messages when a download is user-cancelled Resolves #1941. --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++++-- osu.Game/Overlays/Direct/DirectPanel.cs | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 634b5bcd20..fa20f779a4 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -292,10 +292,12 @@ namespace osu.Game.Beatmaps currentDownloads.Remove(request); }; - request.Failure += data => + request.Failure += error => { + if (error is OperationCanceledException) return; + downloadNotification.State = ProgressNotificationState.Completed; - Logger.Error(data, "Failed to get beatmap download information"); + Logger.Error(error, "Beatmap download failed!"); currentDownloads.Remove(request); }; diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 7dd6be8dc6..64a36f5671 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -180,7 +180,6 @@ namespace osu.Game.Overlays.Direct { progressBar.Current.Value = 0; progressBar.FadeOut(500); - Logger.Error(e, "Failed to get beatmap download information"); }; request.DownloadProgressed += progress => progressBar.Current.Value = progress; From 4780c3f8c6d41a36762b31629e7cfc8b6fd09c20 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 22 Jan 2018 13:41:47 +0900 Subject: [PATCH 5/8] Disable TestCaseWaveform --- osu.Game.Tests/Visual/TestCaseWaveform.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseWaveform.cs b/osu.Game.Tests/Visual/TestCaseWaveform.cs index 87492e2332..dd5420400f 100644 --- a/osu.Game.Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game.Tests/Visual/TestCaseWaveform.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; @@ -15,6 +16,7 @@ using osu.Game.Screens.Edit.Screens.Compose.Timeline; namespace osu.Game.Tests.Visual { + [Ignore("CI regularly hangs on this TestCase...")] public class TestCaseWaveform : OsuTestCase { private readonly Bindable beatmapBacking = new Bindable(); From 3d4e2d400cd9896803a2dbf0ce31f928f40b20a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Jan 2018 13:52:10 +0900 Subject: [PATCH 6/8] Remove unused using --- osu.Game/Overlays/Direct/DirectPanel.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 64a36f5671..9249c5a2c4 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -16,7 +16,6 @@ using osu.Game.Graphics.Sprites; using OpenTK.Graphics; using osu.Framework.Input; using osu.Game.Graphics.UserInterface; -using osu.Framework.Logging; using osu.Game.Online.API.Requests; using osu.Framework.Configuration; using osu.Framework.Audio.Track; From 82c882288824696b0e6011f9ee57e38ad3bdf2b4 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 22 Jan 2018 08:04:14 +0100 Subject: [PATCH 7/8] we need to go back reverted change and instead check `DeletePending` when retrieving existing online IDs --- osu.Game/Overlays/DirectOverlay.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index efd54bec82..05b5bba09c 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -298,15 +298,13 @@ namespace osu.Game.Overlays Task.Run(() => { var onlineIds = response.Select(r => r.OnlineBeatmapSetID).ToList(); - var presentSets = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID)).ToList(); - - var responseSets = response.Select(r => r.ToBeatmapSet(rulesets)).ToList(); - var finalSets = responseSets.Where(b => !presentSets.Any(s => s.OnlineBeatmapSetID == b.OnlineBeatmapSetID && !s.DeletePending)).ToList(); + var presentOnlineIds = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID) && !s.DeletePending).Select(r => r.OnlineBeatmapSetID).ToList(); + var sets = response.Select(r => r.ToBeatmapSet(rulesets)).Where(b => !presentOnlineIds.Contains(b.OnlineBeatmapSetID)).ToList(); // may not need scheduling; loads async internally. Schedule(() => { - BeatmapSets = finalSets; + BeatmapSets = sets; recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value); }); }); From 32b540268e3b3ec9817ef167db65eea0ae6e1ea8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Jan 2018 18:46:59 +0900 Subject: [PATCH 8/8] Add more human-like catch autoplay support Closes #1611 --- osu.Game.Rulesets.Catch/CatchInputManager.cs | 1 - .../Replays/CatchAutoGenerator.cs | 72 ++++++++++++++++++- .../Replays/CatchFramedReplayInputHandler.cs | 28 ++++++-- .../Replays/CatchReplayFrame.cs | 4 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 12 ++-- 5 files changed, 97 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs index f57952f95e..fa8958687c 100644 --- a/osu.Game.Rulesets.Catch/CatchInputManager.cs +++ b/osu.Game.Rulesets.Catch/CatchInputManager.cs @@ -23,6 +23,5 @@ namespace osu.Game.Rulesets.Catch MoveRight, [Description("Engage dash")] Dash, - PositionUpdate } } diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs index bc53e6e869..f8ca75fae9 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs @@ -1,9 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Linq; +using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Replays; using osu.Game.Users; @@ -23,15 +26,78 @@ namespace osu.Game.Rulesets.Catch.Replays public override Replay Generate() { + // todo: add support for HT DT + const double dash_speed = CatcherArea.Catcher.BASE_SPEED; + const double movement_speed = dash_speed / 2; + float lastPosition = 0.5f; + double lastTime = 0; + // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled - Replay.Frames.Add(new CatchReplayFrame(-100000, 0)); + Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition)); + + void moveToNext(CatchHitObject h) + { + float positionChange = Math.Abs(lastPosition - h.X); + double timeAvailable = h.StartTime - lastTime; + + //So we can either make it there without a dash or not. + double speedRequired = positionChange / timeAvailable; + + bool dashRequired = speedRequired > movement_speed && h.StartTime != 0; + + // todo: get correct catcher size, based on difficulty CS. + const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f; + + if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X) + { + //we are already in the correct range. + lastTime = h.StartTime; + Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition)); + return; + } + + if (h is BananaShower.Banana) + { + // auto bananas unrealistically warp to catch 100% combo. + Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); + } + else if (h.HyperDash) + { + Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition, ReplayButtonState.Right1)); + Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); + } + else if (dashRequired) + { + //we do a movement in two parts - the dash part then the normal part... + double timeAtNormalSpeed = positionChange / movement_speed; + double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable; + double timeAtDashSpeed = timeWeNeedToSave / 2; + + float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable); + + //dash movement + Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, ReplayButtonState.Left1)); + Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition)); + Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); + } + else + { + double timeBefore = positionChange / movement_speed; + + Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition, ReplayButtonState.Right1)); + Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); + } + + lastTime = h.StartTime; + lastPosition = h.X; + } foreach (var obj in Beatmap.HitObjects) { switch (obj) { case Fruit _: - Replay.Frames.Add(new CatchReplayFrame(obj.StartTime, obj.X)); + moveToNext(obj); break; } @@ -42,7 +108,7 @@ namespace osu.Game.Rulesets.Catch.Replays case BananaShower.Banana _: case TinyDroplet _: case Droplet _: - Replay.Frames.Add(new CatchReplayFrame(nestedObj.StartTime, nestedObj.X)); + moveToNext(nestedObj); break; } } diff --git a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs index 146e31fa69..2f296a2504 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs @@ -14,15 +14,29 @@ namespace osu.Game.Rulesets.Catch.Replays { } - public override List GetPendingStates() => new List + public override List GetPendingStates() { - new CatchReplayState + if (!Position.HasValue) return new List(); + + var action = new List(); + + if (CurrentFrame.ButtonState == ReplayButtonState.Left1) + action.Add(CatchAction.Dash); + + if (Position.Value.X > CurrentFrame.Position.X) + action.Add(CatchAction.MoveRight); + else if (Position.Value.X < CurrentFrame.Position.X) + action.Add(CatchAction.MoveLeft); + + return new List { - PressedActions = new List { CatchAction.PositionUpdate }, - CatcherX = ((CatchReplayFrame)CurrentFrame).MouseX - }, - new CatchReplayState { PressedActions = new List() }, - }; + new CatchReplayState + { + PressedActions = action, + CatcherX = Position.Value.X + }, + }; + } public class CatchReplayState : ReplayState { diff --git a/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs b/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs index c47f60ec3c..0194fc93a4 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs @@ -9,8 +9,8 @@ namespace osu.Game.Rulesets.Catch.Replays { public override bool IsImportant => MouseX > 0; - public CatchReplayFrame(double time, float? x = null) - : base(time, x ?? -1, null, ReplayButtonState.None) + public CatchReplayFrame(double time, float? x = null, ReplayButtonState button = ReplayButtonState.None) + : base(time, x ?? -1, null, button) { } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 17c78f3aa0..5252ba294a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -21,7 +21,7 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { - public class CatcherArea : Container, IKeyBindingHandler + public class CatcherArea : Container { public const float CATCHER_SIZE = 172; @@ -84,16 +84,14 @@ namespace osu.Game.Rulesets.Catch.UI } } - public bool OnPressed(CatchAction action) + protected override void Update() { - if (action != CatchAction.PositionUpdate) return false; + base.Update(); - CatchFramedReplayInputHandler.CatchReplayState state = (CatchFramedReplayInputHandler.CatchReplayState)GetContainingInputManager().CurrentState; + var state = GetContainingInputManager().CurrentState as CatchFramedReplayInputHandler.CatchReplayState; - if (state.CatcherX.HasValue) + if (state?.CatcherX != null) MovableCatcher.X = state.CatcherX.Value; - - return true; } public bool OnReleased(CatchAction action) => false;