diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index 972677a6f1..89821a10fb 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -93,6 +93,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => { + // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) var diff = slider.PositionAt(t) - slider.LazyEndPosition.Value; float dist = diff.Length; diff --git a/osu.Game.Tests/Visual/TestCaseSettings.cs b/osu.Game.Tests/Visual/TestCaseSettings.cs index 13698b645f..15a60386ef 100644 --- a/osu.Game.Tests/Visual/TestCaseSettings.cs +++ b/osu.Game.Tests/Visual/TestCaseSettings.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Overlays; namespace osu.Game.Tests.Visual @@ -8,16 +10,30 @@ namespace osu.Game.Tests.Visual public class TestCaseSettings : OsuTestCase { private readonly SettingsOverlay settings; + private readonly DialogOverlay dialogOverlay; + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent); public TestCaseSettings() { - Children = new[] { settings = new MainSettings() }; + settings = new MainSettings + { + State = Visibility.Visible + }; + Add(dialogOverlay = new DialogOverlay + { + Depth = -1 + }); } - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load() { - base.LoadComplete(); - settings.ToggleVisibility(); + dependencies.Cache(dialogOverlay); + + Add(settings); } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index a1ad708304..0325785016 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -341,6 +341,61 @@ namespace osu.Game.Beatmaps } } + public void UndeleteAll() + { + var deleteMaps = QueryBeatmapSets(bs => bs.DeletePending).ToList(); + + if (!deleteMaps.Any()) return; + + var notification = new ProgressNotification + { + CompletionText = "Restored all deleted beatmaps!", + Progress = 0, + State = ProgressNotificationState.Active, + }; + + PostNotification?.Invoke(notification); + + int i = 0; + + foreach (var bs in deleteMaps) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + notification.Text = $"Restoring ({i} of {deleteMaps.Count})"; + notification.Progress = (float)++i / deleteMaps.Count; + Undelete(bs); + } + + notification.State = ProgressNotificationState.Completed; + } + + public void Undelete(BeatmapSetInfo beatmapSet) + { + if (beatmapSet.Protected) + return; + + lock (importContext) + { + var context = importContext.Value; + + using (var transaction = context.BeginTransaction()) + { + context.ChangeTracker.AutoDetectChangesEnabled = false; + + var iFiles = new FileStore(() => context, storage); + var iBeatmaps = createBeatmapStore(() => context); + + undelete(iBeatmaps, iFiles, beatmapSet); + + context.ChangeTracker.AutoDetectChangesEnabled = true; + context.SaveChanges(transaction); + } + } + } + /// /// Delete a beatmap difficulty. /// diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index e3be23ebc6..9639907914 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -31,6 +31,8 @@ namespace osu.Game.Overlays.Mods protected readonly OsuSpriteText MultiplierLabel; private readonly FillFlowContainer footerContainer; + protected override bool BlockPassThroughKeyboard => false; + protected readonly FillFlowContainer ModSectionsContainer; public readonly Bindable> SelectedMods = new Bindable>(); diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 23bec53014..d913895159 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -13,7 +13,6 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; -using System.Threading; namespace osu.Game.Overlays.Music { @@ -153,11 +152,6 @@ namespace osu.Game.Overlays.Music var track = beatmapBacking.Value.Track; track.Restart(); - - // this is temporary until we have blocking (async.Wait()) audio component methods. - // then we can call RestartAsync().Wait() or the blocking version above. - while (!track.IsRunning) - Thread.Sleep(1); } } diff --git a/osu.Game/Overlays/Settings/DangerousSettingsButton.cs b/osu.Game/Overlays/Settings/DangerousSettingsButton.cs new file mode 100644 index 0000000000..7c324658a3 --- /dev/null +++ b/osu.Game/Overlays/Settings/DangerousSettingsButton.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Overlays.Settings +{ + /// + /// A with pink colours to mark dangerous/destructive actions. + /// + public class DangerousSettingsButton : SettingsButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Pink; + + Triangles.ColourDark = colours.PinkDark; + Triangles.ColourLight = colours.PinkLight; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DeleteAllBeatmapsDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DeleteAllBeatmapsDialog.cs new file mode 100644 index 0000000000..8ae520651a --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DeleteAllBeatmapsDialog.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Game.Graphics; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Overlays.Settings.Sections.Maintenance +{ + public class DeleteAllBeatmapsDialog : PopupDialog + { + public DeleteAllBeatmapsDialog(Action deleteAction) + { + BodyText = "Everything?"; + + Icon = FontAwesome.fa_trash_o; + HeaderText = @"Confirm deletion of"; + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton + { + Text = @"Yes. Go for it.", + Action = deleteAction + }, + new PopupDialogCancelButton + { + Text = @"No! Abort mission!", + }, + }; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 4f4f381ae1..e288445c6d 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -15,11 +15,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private TriangleButton importButton; private TriangleButton deleteButton; private TriangleButton restoreButton; + private TriangleButton undeleteButton; protected override string Header => "General"; [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) + private void load(BeatmapManager beatmaps, DialogOverlay dialogOverlay) { Children = new Drawable[] { @@ -33,13 +34,16 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance .ContinueWith(t => Schedule(() => importButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); } }, - deleteButton = new SettingsButton + deleteButton = new DangerousSettingsButton { Text = "Delete ALL beatmaps", Action = () => { - deleteButton.Enabled.Value = false; - Task.Run(() => beatmaps.DeleteAll()).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true)); + dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => + { + deleteButton.Enabled.Value = false; + Task.Run(() => beatmaps.DeleteAll()).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true)); + })); } }, restoreButton = new SettingsButton @@ -55,6 +59,15 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); } }, + undeleteButton = new SettingsButton + { + Text = "Restore all recently deleted beatmaps", + Action = () => + { + undeleteButton.Enabled.Value = false; + Task.Run(() => beatmaps.UndeleteAll()).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); + } + }, }; } } diff --git a/osu.Game/Overlays/WaveOverlayContainer.cs b/osu.Game/Overlays/WaveOverlayContainer.cs index 50150b6660..3f9703a523 100644 --- a/osu.Game/Overlays/WaveOverlayContainer.cs +++ b/osu.Game/Overlays/WaveOverlayContainer.cs @@ -28,6 +28,8 @@ namespace osu.Game.Overlays private readonly Container contentContainer; + protected override bool BlockPassThroughKeyboard => true; + protected override Container Content => contentContainer; protected Color4 FirstWaveColour diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index e49ebb5590..6969cd915b 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -124,44 +124,21 @@ namespace osu.Game.Screens.Play }, }; - Retries = 0; + updateRetryCount(); } + private int retries; + public int Retries { set { - if (retryCounterContainer != null) - { - // "You've retried 1,065 times in this session" - // "You've retried 1 time in this session" + if (value == retries) + return; - retryCounterContainer.Children = new Drawable[] - { - new OsuSpriteText - { - Text = "You've retried ", - Shadow = true, - ShadowColour = new Color4(0, 0, 0, 0.25f), - TextSize = 18 - }, - new OsuSpriteText - { - Text = $"{value:n0}", - Font = @"Exo2.0-Bold", - Shadow = true, - ShadowColour = new Color4(0, 0, 0, 0.25f), - TextSize = 18 - }, - new OsuSpriteText - { - Text = $" time{(value == 1 ? "" : "s")} in this session", - Shadow = true, - ShadowColour = new Color4(0, 0, 0, 0.25f), - TextSize = 18 - } - }; - } + retries = value; + if (retryCounterContainer != null) + updateRetryCount(); } } @@ -252,6 +229,38 @@ namespace osu.Game.Screens.Play selectionIndex = InternalButtons.IndexOf(button); } + private void updateRetryCount() + { + // "You've retried 1,065 times in this session" + // "You've retried 1 time in this session" + + retryCounterContainer.Children = new Drawable[] + { + new OsuSpriteText + { + Text = "You've retried ", + Shadow = true, + ShadowColour = new Color4(0, 0, 0, 0.25f), + TextSize = 18 + }, + new OsuSpriteText + { + Text = $"{retries:n0}", + Font = @"Exo2.0-Bold", + Shadow = true, + ShadowColour = new Color4(0, 0, 0, 0.25f), + TextSize = 18 + }, + new OsuSpriteText + { + Text = $" time{(retries == 1 ? "" : "s")} in this session", + Shadow = true, + ShadowColour = new Color4(0, 0, 0, 0.25f), + TextSize = 18 + } + }; + } + private class Button : DialogButton { protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b5b09504da..340fc39d52 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -17,7 +17,6 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Backgrounds; using System; using System.Linq; -using System.Threading; using System.Threading.Tasks; using osu.Framework.Threading; using osu.Game.Rulesets.Mods; @@ -161,8 +160,8 @@ namespace osu.Game.Screens.Play OnRetry = Restart, OnQuit = Exit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, - Retries = RestartCount, OnPause = () => { + pauseContainer.Retries = RestartCount; hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, OnResume = () => { @@ -327,11 +326,6 @@ namespace osu.Game.Screens.Play { adjustableSourceClock.Reset(); - // this is temporary until we have blocking (async.Wait()) audio component methods. - // then we can call ResetAsync().Wait() or the blocking version above. - while (adjustableSourceClock.IsRunning) - Thread.Sleep(1); - Schedule(() => { decoupledClock.ChangeSource(adjustableSourceClock); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 571249025f..199d51a8c1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -267,6 +267,7 @@ + @@ -306,6 +307,7 @@ +