From 5bf513eba83e16d1e16231cd776bb9bc5727550a Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 17 May 2019 11:24:34 +0900 Subject: [PATCH 01/44] Don't track immediately when entering mode --- .../UserInterface/TestCaseButtonSystem.cs | 21 ++++++++++++++++++- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs index 04aa8bce7e..814558547a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Shapes; using osu.Game.Screens.Menu; +using osuTK; using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface @@ -42,7 +43,25 @@ namespace osu.Game.Tests.Visual.UserInterface buttons.SetOsuLogo(logo); foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType().Skip(1)) - AddStep($"State to {s}", () => buttons.State = s); + AddStep($"State to {s}", () => + { + buttons.State = s; + + if (buttons.State == ButtonSystemState.EnteringMode) + { + buttons.FadeOut(400, Easing.InSine); + buttons.MoveTo(new Vector2(-800, 0), 400, Easing.InSine); + logo.FadeOut(300, Easing.InSine) + .ScaleTo(0.2f, 300, Easing.InSine); + } + else + { + buttons.FadeIn(400, Easing.OutQuint); + buttons.MoveTo(new Vector2(0), 400, Easing.OutQuint); + logo.FadeColour(Color4.White, 100, Easing.OutQuint); + logo.FadeIn(100, Easing.OutQuint); + } + }); } } } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index a098d42c83..9784e8cfcb 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -332,7 +332,7 @@ namespace osu.Game.Screens.Menu break; case ButtonSystemState.EnteringMode: - logoTrackingContainer.StartTracking(logo, 0, Easing.In); + logoTrackingContainer.StartTracking(logo, 400, Easing.InSine); break; } } From b7aed0a0147e8881a05cac4404ea3a22d8addcf0 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 17 May 2019 12:21:34 +0900 Subject: [PATCH 02/44] Interpolate to tracking position on from Initial button state --- osu.Game/Screens/Menu/ButtonSystem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 9784e8cfcb..900e5ae514 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -332,7 +332,8 @@ namespace osu.Game.Screens.Menu break; case ButtonSystemState.EnteringMode: - logoTrackingContainer.StartTracking(logo, 400, Easing.InSine); + // When coming from the Initial (untracked) state, interpolate to the tracking position over a brief duration instead of tracking immediately. + logoTrackingContainer.StartTracking(logo, lastState == ButtonSystemState.Initial ? 400 : 0, Easing.InSine); break; } } From 15c75b444232be13b2d9e6fa4b04cb0462b23608 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 19 Jun 2019 18:33:51 +0200 Subject: [PATCH 03/44] Add basic score import from stable --- osu.Game/Beatmaps/BeatmapManager.cs | 2 ++ osu.Game/Database/ArchiveModelManager.cs | 13 ++++++-- osu.Game/OsuGame.cs | 1 + .../Sections/Maintenance/GeneralSettings.cs | 33 +++++++++++++++++-- osu.Game/Scoring/ScoreManager.cs | 10 ++++-- osu.Game/Skinning/SkinManager.cs | 2 ++ 6 files changed, 54 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 3734c8d05c..b6fa0ec95a 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -62,6 +62,8 @@ namespace osu.Game.Beatmaps protected override string ImportFromStablePath => "Songs"; + protected override bool StableDirectoryBased => true; + private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 1c8e722589..2a329cd5b4 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -546,6 +546,11 @@ namespace osu.Game.Database /// protected virtual string ImportFromStablePath => null; + /// + /// Does stable import look for directories rather than files + /// + protected abstract bool StableDirectoryBased { get; } + /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. /// @@ -566,7 +571,11 @@ namespace osu.Game.Database return Task.CompletedTask; } - return Task.Run(async () => await Import(stable.GetDirectories(ImportFromStablePath).Select(f => stable.GetFullPath(f)).ToArray())); + return Task.Run(async () => + { + var paths = StableDirectoryBased ? stable.GetDirectories(ImportFromStablePath) : stable.GetFiles(ImportFromStablePath); + await Import(paths.Select(f => stable.GetFullPath(f)).ToArray()); + }); } #endregion diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f38eecef81..75f17fdbe3 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -360,6 +360,7 @@ namespace osu.Game BeatmapManager.PresentImport = items => PresentBeatmap(items.First()); ScoreManager.PostNotification = n => notifications?.Post(n); + ScoreManager.GetStableStorage = GetStorageForStableInstall; ScoreManager.PresentImport = items => PresentScore(items.First()); Container logoContainer; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 398a091486..832673703b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.Scoring; using osu.Game.Skinning; namespace osu.Game.Overlays.Settings.Sections.Maintenance @@ -16,14 +17,16 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance protected override string Header => "General"; private TriangleButton importBeatmapsButton; + private TriangleButton importScoresButton; private TriangleButton importSkinsButton; - private TriangleButton deleteSkinsButton; private TriangleButton deleteBeatmapsButton; + private TriangleButton deleteScoresButton; + private TriangleButton deleteSkinsButton; private TriangleButton restoreButton; private TriangleButton undeleteButton; [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps, SkinManager skins, DialogOverlay dialogOverlay) + private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, DialogOverlay dialogOverlay) { if (beatmaps.SupportsImportFromStable) { @@ -51,6 +54,32 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }); + if (scores.SupportsImportFromStable) + { + Add(importScoresButton = new SettingsButton + { + Text = "Import scores from stable", + Action = () => + { + importScoresButton.Enabled.Value = false; + scores.ImportFromStableAsync().ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); + } + }); + } + + Add(deleteScoresButton = new DangerousSettingsButton + { + Text = "Delete ALL scores", + Action = () => + { + dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => + { + deleteScoresButton.Enabled.Value = false; + Task.Run(() => scores.Delete(scores.GetAllUsableScores())).ContinueWith(t => Schedule(() => deleteScoresButton.Enabled.Value = true)); + })); + } + }); + if (skins.SupportsImportFromStable) { Add(importSkinsButton = new SettingsButton diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 6b737dc734..a0a7e956f2 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -22,7 +22,9 @@ namespace osu.Game.Scoring protected override string[] HashableFileTypes => new[] { ".osr" }; - protected override string ImportFromStablePath => "Replays"; + protected override string ImportFromStablePath => @"Data\r"; + + protected override bool StableDirectoryBased => false; private readonly RulesetStore rulesets; private readonly Func beatmaps; @@ -36,10 +38,12 @@ namespace osu.Game.Scoring protected override ScoreInfo CreateModel(ArchiveReader archive) { - if (archive == null) + string filename = archive?.Filenames.FirstOrDefault(f => f.EndsWith(".osr")); + + if (filename == null) return null; - using (var stream = archive.GetStream(archive.Filenames.First(f => f.EndsWith(".osr")))) + using (var stream = archive.GetStream(filename)) { try { diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 73cc47ea47..dafaf0c9dc 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -32,6 +32,8 @@ namespace osu.Game.Skinning protected override string ImportFromStablePath => "Skins"; + protected override bool StableDirectoryBased => true; + public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcHost importHost, AudioManager audio) : base(storage, contextFactory, new SkinStore(contextFactory, storage), importHost) { From ef2e93d5c7ffafe790c7a63a3e2f6e9fc932560f Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 19 Jun 2019 19:29:47 +0200 Subject: [PATCH 04/44] Improve handling of null models when importing --- osu.Game/Database/ArchiveModelManager.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 2a329cd5b4..41e141129d 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -160,7 +160,8 @@ namespace osu.Game.Database lock (imported) { - imported.Add(model); + if (model != null) + imported.Add(model); current++; notification.Text = $"Imported {current} of {paths.Length} {HumanisedModelName}s"; @@ -243,7 +244,7 @@ namespace osu.Game.Database /// /// The archive to be imported. /// An optional cancellation token. - public Task Import(ArchiveReader archive, CancellationToken cancellationToken = default) + public async Task Import(ArchiveReader archive, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -267,7 +268,7 @@ namespace osu.Game.Database return null; } - return Import(model, archive, cancellationToken); + return await Import(model, archive, cancellationToken); } /// From 0cb66d522a7dcab06d88e41459d6eeba911712b2 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 19 Jun 2019 20:36:00 +0200 Subject: [PATCH 05/44] Check if path can be imported before trying --- osu.Game/Database/ArchiveModelManager.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 41e141129d..1bb243a8f3 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -150,7 +150,7 @@ namespace osu.Game.Database var imported = new List(); - await Task.WhenAll(paths.Select(async path => + await Task.WhenAll(paths.Where(canImportPath).Select(async path => { notification.CancellationToken.ThrowIfCancellationRequested(); @@ -160,8 +160,7 @@ namespace osu.Game.Database lock (imported) { - if (model != null) - imported.Add(model); + imported.Add(model); current++; notification.Text = $"Imported {current} of {paths.Length} {HumanisedModelName}s"; @@ -201,6 +200,8 @@ namespace osu.Game.Database notification.State = ProgressNotificationState.Completed; } + + bool canImportPath(string path) => StableDirectoryBased || HandledExtensions.Any(ext => Path.GetExtension(path)?.ToLowerInvariant() == ext); } /// From 8d62ce8967abcc68786d136793ef67876c597769 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 19 Jun 2019 20:38:43 +0200 Subject: [PATCH 06/44] Remove now unneeded check against file extension --- osu.Game/Scoring/ScoreManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index a0a7e956f2..77b7ed33dd 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -38,12 +38,10 @@ namespace osu.Game.Scoring protected override ScoreInfo CreateModel(ArchiveReader archive) { - string filename = archive?.Filenames.FirstOrDefault(f => f.EndsWith(".osr")); - - if (filename == null) + if (archive == null) return null; - using (var stream = archive.GetStream(filename)) + using (var stream = archive.GetStream(archive.Filenames.FirstOrDefault(f => f.EndsWith(".osr")))) { try { From c1c19243cd28af8ec11664af84dcfdb69bea4799 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 19 Jun 2019 20:40:30 +0200 Subject: [PATCH 07/44] Change FirstOrDefault back to First --- osu.Game/Scoring/ScoreManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 77b7ed33dd..a8124968d8 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -41,7 +41,7 @@ namespace osu.Game.Scoring if (archive == null) return null; - using (var stream = archive.GetStream(archive.Filenames.FirstOrDefault(f => f.EndsWith(".osr")))) + using (var stream = archive.GetStream(archive.Filenames.First(f => f.EndsWith(".osr")))) { try { From 99f1a94797819a3e24ec217c9feea2890eed6a35 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 19 Jun 2019 20:50:50 +0200 Subject: [PATCH 08/44] Fix notification progress bar --- osu.Game/Database/ArchiveModelManager.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 1bb243a8f3..b82e9c3d0b 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -146,11 +146,12 @@ namespace osu.Game.Database notification.Progress = 0; notification.Text = "Import is initialising..."; + string[] filteredPaths = paths.Where(canImportPath).ToArray(); int current = 0; var imported = new List(); - await Task.WhenAll(paths.Where(canImportPath).Select(async path => + await Task.WhenAll(filteredPaths.Select(async path => { notification.CancellationToken.ThrowIfCancellationRequested(); @@ -163,8 +164,8 @@ namespace osu.Game.Database imported.Add(model); current++; - notification.Text = $"Imported {current} of {paths.Length} {HumanisedModelName}s"; - notification.Progress = (float)current / paths.Length; + notification.Text = $"Imported {current} of {filteredPaths.Length} {HumanisedModelName}s"; + notification.Progress = (float)current / filteredPaths.Length; } } catch (TaskCanceledException) From f1f03dd5411ef12a1923519e6435a50d290fb521 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Fri, 21 Jun 2019 17:01:11 +0200 Subject: [PATCH 09/44] Remove async from Import method --- osu.Game/Database/ArchiveModelManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index b82e9c3d0b..e22aa92546 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -246,7 +246,7 @@ namespace osu.Game.Database /// /// The archive to be imported. /// An optional cancellation token. - public async Task Import(ArchiveReader archive, CancellationToken cancellationToken = default) + public Task Import(ArchiveReader archive, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -256,7 +256,7 @@ namespace osu.Game.Database { model = CreateModel(archive); - if (model == null) return null; + if (model == null) return Task.FromResult(null); model.Hash = computeHash(archive); } @@ -270,7 +270,7 @@ namespace osu.Game.Database return null; } - return await Import(model, archive, cancellationToken); + return Import(model, archive, cancellationToken); } /// From 802da225d48c387907cccb3666cccb010135d5dd Mon Sep 17 00:00:00 2001 From: HoLLy Date: Fri, 21 Jun 2019 17:32:47 +0200 Subject: [PATCH 10/44] Move responsibility for selecting paths to model managers --- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++-- osu.Game/Database/ArchiveModelManager.cs | 21 +++++++-------------- osu.Game/Scoring/ScoreManager.cs | 7 +++++-- osu.Game/Skinning/SkinManager.cs | 4 ++-- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index b6fa0ec95a..e357f741d3 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -62,8 +62,6 @@ namespace osu.Game.Beatmaps protected override string ImportFromStablePath => "Songs"; - protected override bool StableDirectoryBased => true; - private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; @@ -96,6 +94,8 @@ namespace osu.Game.Beatmaps updateQueue = new BeatmapUpdateQueue(api); } + protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); + protected override Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default) { if (archive != null) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index e22aa92546..75bc656862 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -146,12 +146,11 @@ namespace osu.Game.Database notification.Progress = 0; notification.Text = "Import is initialising..."; - string[] filteredPaths = paths.Where(canImportPath).ToArray(); int current = 0; var imported = new List(); - await Task.WhenAll(filteredPaths.Select(async path => + await Task.WhenAll(paths.Select(async path => { notification.CancellationToken.ThrowIfCancellationRequested(); @@ -164,8 +163,8 @@ namespace osu.Game.Database imported.Add(model); current++; - notification.Text = $"Imported {current} of {filteredPaths.Length} {HumanisedModelName}s"; - notification.Progress = (float)current / filteredPaths.Length; + notification.Text = $"Imported {current} of {paths.Length} {HumanisedModelName}s"; + notification.Progress = (float)current / paths.Length; } } catch (TaskCanceledException) @@ -201,8 +200,6 @@ namespace osu.Game.Database notification.State = ProgressNotificationState.Completed; } - - bool canImportPath(string path) => StableDirectoryBased || HandledExtensions.Any(ext => Path.GetExtension(path)?.ToLowerInvariant() == ext); } /// @@ -537,7 +534,7 @@ namespace osu.Game.Database /// /// Set a storage with access to an osu-stable install for import purposes. /// - public Func GetStableStorage { private get; set; } + public Func GetStableStorage { protected get; set; } /// /// Denotes whether an osu-stable installation is present to perform automated imports from. @@ -550,9 +547,9 @@ namespace osu.Game.Database protected virtual string ImportFromStablePath => null; /// - /// Does stable import look for directories rather than files + /// Selects paths to import from. /// - protected abstract bool StableDirectoryBased { get; } + protected abstract IEnumerable GetStableImportPaths(); /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. @@ -574,11 +571,7 @@ namespace osu.Game.Database return Task.CompletedTask; } - return Task.Run(async () => - { - var paths = StableDirectoryBased ? stable.GetDirectories(ImportFromStablePath) : stable.GetFiles(ImportFromStablePath); - await Import(paths.Select(f => stable.GetFullPath(f)).ToArray()); - }); + return Task.Run(async () => await Import(GetStableImportPaths().Select(f => stable.GetFullPath(f)).ToArray())); } #endregion diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index a8124968d8..bb1b15e9bd 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; @@ -24,8 +25,6 @@ namespace osu.Game.Scoring protected override string ImportFromStablePath => @"Data\r"; - protected override bool StableDirectoryBased => false; - private readonly RulesetStore rulesets; private readonly Func beatmaps; @@ -55,6 +54,10 @@ namespace osu.Game.Scoring } } + protected override IEnumerable GetStableImportPaths() + => GetStableStorage().GetFiles(ImportFromStablePath) + .Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.InvariantCultureIgnoreCase) ?? false)); + public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store); public List GetAllUsableScores() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList(); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index dafaf0c9dc..899bab8b94 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -32,8 +32,6 @@ namespace osu.Game.Skinning protected override string ImportFromStablePath => "Skins"; - protected override bool StableDirectoryBased => true; - public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcHost importHost, AudioManager audio) : base(storage, contextFactory, new SkinStore(contextFactory, storage), importHost) { @@ -56,6 +54,8 @@ namespace osu.Game.Skinning }; } + protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); + /// /// Returns a list of all usable s. Includes the special default skin plus all skins from . /// From d99f4d1a8764a6faa8cda345318d67a22fd35626 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Fri, 21 Jun 2019 17:42:54 +0200 Subject: [PATCH 11/44] Change import button to mention replays instead of scores --- .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 832673703b..e3f5acc8ac 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Add(importScoresButton = new SettingsButton { - Text = "Import scores from stable", + Text = "Import replays from stable", Action = () => { importScoresButton.Enabled.Value = false; From 12350d18b522f073074b28e25f0daa45f1ac3d15 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Thu, 27 Jun 2019 14:41:11 +0200 Subject: [PATCH 12/44] Don't remove imported archives by default --- osu.Game/Beatmaps/BeatmapManager.cs | 2 ++ osu.Game/Database/ArchiveModelManager.cs | 7 ++++++- osu.Game/Skinning/SkinManager.cs | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index da47ce7aab..cbaecdc8a7 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -83,6 +83,8 @@ namespace osu.Game.Beatmaps protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); + protected override bool ShouldRemoveArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz"; + protected override Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default) { if (archive != null) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index b1756c1790..939333c6f4 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -176,7 +176,7 @@ namespace osu.Game.Database // TODO: Add a check to prevent files from storage to be deleted. try { - if (import != null && File.Exists(path)) + if (import != null && File.Exists(path) && ShouldRemoveArchive(path)) File.Delete(path); } catch (Exception e) @@ -503,6 +503,11 @@ namespace osu.Game.Database /// protected abstract IEnumerable GetStableImportPaths(); + /// + /// Should this archive be removed after importing? + /// + protected virtual bool ShouldRemoveArchive(string path) => false; + /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. /// diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 899bab8b94..cf1e9368bc 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -56,6 +56,8 @@ namespace osu.Game.Skinning protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); + protected override bool ShouldRemoveArchive(string path) => true; + /// /// Returns a list of all usable s. Includes the special default skin plus all skins from . /// From 79fc143422815a9b1335f33c87cfc857b1ad14b8 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Sun, 30 Jun 2019 16:52:39 +0200 Subject: [PATCH 13/44] Only remove .osk files when importing skin archives --- osu.Game/Skinning/SkinManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index cf1e9368bc..00e6fddc6a 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Linq.Expressions; using System.Threading; @@ -56,7 +57,7 @@ namespace osu.Game.Skinning protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); - protected override bool ShouldRemoveArchive(string path) => true; + protected override bool ShouldRemoveArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osk"; /// /// Returns a list of all usable s. Includes the special default skin plus all skins from . From 6391d21af1b5c671fc99d6cfc9d483971840b6f6 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 3 Jul 2019 15:54:21 +0900 Subject: [PATCH 14/44] Remove test used for visualization --- .../UserInterface/TestSceneButtonSystem.cs | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs index 6c4d9b20f7..c8cc864089 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Shapes; using osu.Game.Screens.Menu; -using osuTK; using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface @@ -43,25 +42,7 @@ namespace osu.Game.Tests.Visual.UserInterface buttons.SetOsuLogo(logo); foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType().Skip(1)) - AddStep($"State to {s}", () => - { - buttons.State = s; - - if (buttons.State == ButtonSystemState.EnteringMode) - { - buttons.FadeOut(400, Easing.InSine); - buttons.MoveTo(new Vector2(-800, 0), 400, Easing.InSine); - logo.FadeOut(300, Easing.InSine) - .ScaleTo(0.2f, 300, Easing.InSine); - } - else - { - buttons.FadeIn(400, Easing.OutQuint); - buttons.MoveTo(new Vector2(0), 400, Easing.OutQuint); - logo.FadeColour(Color4.White, 100, Easing.OutQuint); - logo.FadeIn(100, Easing.OutQuint); - } - }); + AddStep($"State to {s}", () => buttons.State = s); } } } From 4ba60ed089636efeb6e276c2a80d7f7aee485d98 Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 3 Jul 2019 17:04:20 +0530 Subject: [PATCH 15/44] Apply currently selected mods to filter leaderboard scores Modifies GetScoresRequest to build query string locally instead of using WebRequest.AddParameter since it doesn't support array parameters --- .../Online/API/Requests/GetScoresRequest.cs | 26 ++++++++------ osu.Game/Screens/Select/BeatmapDetailArea.cs | 2 ++ .../Select/Leaderboards/BeatmapLeaderboard.cs | 35 ++++++++++++++++++- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 0b6f65a0e0..2de0fcef9c 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -5,8 +5,10 @@ using System; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Screens.Select.Leaderboards; -using osu.Framework.IO.Network; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets.Mods; +using System.Text; +using System.Collections.Generic; namespace osu.Game.Online.API.Requests { @@ -15,8 +17,9 @@ namespace osu.Game.Online.API.Requests private readonly BeatmapInfo beatmap; private readonly BeatmapLeaderboardScope scope; private readonly RulesetInfo ruleset; + private readonly IEnumerable mods; - public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global) + public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable mods = null) { if (!beatmap.OnlineBeatmapID.HasValue) throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); @@ -27,6 +30,7 @@ namespace osu.Game.Online.API.Requests this.beatmap = beatmap; this.scope = scope; this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset)); + this.mods = mods ?? Array.Empty(); Success += onSuccess; } @@ -37,17 +41,19 @@ namespace osu.Game.Online.API.Requests score.Beatmap = beatmap; } - protected override WebRequest CreateWebRequest() + protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores{createQueryParameters()}"; + + private string createQueryParameters() { - var req = base.CreateWebRequest(); + StringBuilder query = new StringBuilder(@"?"); - req.Timeout = 30000; - req.AddParameter(@"type", scope.ToString().ToLowerInvariant()); - req.AddParameter(@"mode", ruleset.ShortName); + query.Append($@"type={scope.ToString().ToLowerInvariant()}&"); + query.Append($@"mode={ruleset.ShortName}&"); - return req; + foreach (var mod in mods) + query.Append($@"mods[]={mod.Acronym}&"); + + return query.ToString().TrimEnd('&'); } - - protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores"; } } diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 477037355c..b66a2ffe0f 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -41,6 +41,8 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.X, OnFilter = (tab, mods) => { + Leaderboard.FilterMods = mods; + switch (tab) { case BeatmapDetailTab.Details: diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index aafa6bb0eb..890cc7e9a3 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -11,6 +11,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Leaderboards; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Scoring; namespace osu.Game.Screens.Select.Leaderboards @@ -36,12 +37,31 @@ namespace osu.Game.Screens.Select.Leaderboards } } + private bool filterMods; + + public bool FilterMods + { + get => filterMods; + set + { + if (value == filterMods) + return; + + filterMods = value; + + UpdateScores(); + } + } + [Resolved] private ScoreManager scoreManager { get; set; } [Resolved] private IBindable ruleset { get; set; } + [Resolved] + private IBindable> mods { get; set; } + [Resolved] private IAPIProvider api { get; set; } @@ -49,6 +69,11 @@ namespace osu.Game.Screens.Select.Leaderboards private void load() { ruleset.ValueChanged += _ => UpdateScores(); + mods.ValueChanged += _ => + { + if (filterMods) + UpdateScores(); + }; } protected override APIRequest FetchScores(Action> scoresCallback) @@ -72,7 +97,15 @@ namespace osu.Game.Screens.Select.Leaderboards return null; } - var req = new GetScoresRequest(Beatmap, ruleset.Value ?? Beatmap.Ruleset, Scope); + IReadOnlyList requestMods = null; + + if (filterMods && mods.Value.Count == 0) + // add nomod for the request + requestMods = new Mod[] { new ModNoMod() }; + else if (filterMods) + requestMods = mods.Value; + + var req = new GetScoresRequest(Beatmap, ruleset.Value ?? Beatmap.Ruleset, Scope, requestMods); req.Success += r => scoresCallback?.Invoke(r.Scores); From 99603ca0b67f29edc9fad584cc1e6a4e1fa5526b Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 4 Jul 2019 04:50:49 +0300 Subject: [PATCH 16/44] Fade out game volume on exiting Invokes 'this.Exit()' on completion (simplify lines) --- osu.Game/Screens/Menu/Intro.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index dab5066c52..2883559bbd 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -33,6 +33,8 @@ namespace osu.Game.Screens.Menu protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); + private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); + private Bindable menuVoice; private Bindable menuMusic; private Track track; @@ -72,6 +74,8 @@ namespace osu.Game.Screens.Menu welcome = audio.Samples.Get(@"welcome"); seeya = audio.Samples.Get(@"seeya"); + + audio.AddAdjustment(AdjustableProperty.Volume, exitingVolumeFade); } private const double delay_step_one = 2300; @@ -161,7 +165,7 @@ namespace osu.Game.Screens.Menu else fadeOutTime = 500; - Scheduler.AddDelayed(this.Exit, fadeOutTime); + this.TransformBindableTo(exitingVolumeFade, 0, fadeOutTime).OnComplete(_ => this.Exit()); //don't want to fade out completely else we will stop running updates. Game.FadeTo(0.01f, fadeOutTime); From b53aeec90de21feca625932e2163d45ab379d757 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 4 Jul 2019 05:18:29 +0300 Subject: [PATCH 17/44] Move audio adjustment inside OnResuming --- osu.Game/Screens/Menu/Intro.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 2883559bbd..f6fbcf6498 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -35,13 +35,16 @@ namespace osu.Game.Screens.Menu private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); + [Resolved] + private AudioManager audio { get; set; } + private Bindable menuVoice; private Bindable menuMusic; private Track track; private WorkingBeatmap introBeatmap; [BackgroundDependencyLoader] - private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) + private void load(OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) { menuVoice = config.GetBindable(OsuSetting.MenuVoice); menuMusic = config.GetBindable(OsuSetting.MenuMusic); @@ -74,8 +77,6 @@ namespace osu.Game.Screens.Menu welcome = audio.Samples.Get(@"welcome"); seeya = audio.Samples.Get(@"seeya"); - - audio.AddAdjustment(AdjustableProperty.Volume, exitingVolumeFade); } private const double delay_step_one = 2300; @@ -165,6 +166,7 @@ namespace osu.Game.Screens.Menu else fadeOutTime = 500; + audio.AddAdjustment(AdjustableProperty.Volume, exitingVolumeFade); this.TransformBindableTo(exitingVolumeFade, 0, fadeOutTime).OnComplete(_ => this.Exit()); //don't want to fade out completely else we will stop running updates. From 32bb9633933cd3398c63ca2faa3a771ea03becc6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 4 Jul 2019 14:33:00 +0900 Subject: [PATCH 18/44] Lock WorkingBeatmap cache to avoid threading issues --- osu.Game/Beatmaps/BeatmapManager.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 860c7fc0fa..ab08d35f52 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -176,20 +176,23 @@ namespace osu.Game.Beatmaps if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - var cached = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID); + lock (workingCache) + { + var cached = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID); - if (cached != null) - return cached; + if (cached != null) + return cached; - if (beatmapInfo.Metadata == null) - beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata; + if (beatmapInfo.Metadata == null) + beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata; - WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(Files.Store, new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager); + WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(Files.Store, new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager); - previous?.TransferTo(working); - workingCache.Add(working); + previous?.TransferTo(working); + workingCache.Add(working); - return working; + return working; + } } /// From 4885f0f0c72c05a1174a521c77c2392dafbbfe8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 4 Jul 2019 15:47:06 +0900 Subject: [PATCH 19/44] Add messaging telling users how to leave changelog comments --- .../Online/TestSceneChangelogOverlay.cs | 1 + .../Requests/Responses/APIChangelogBuild.cs | 2 + .../Changelog/ChangelogSingleBuild.cs | 6 +- osu.Game/Overlays/Changelog/Comments.cs | 79 +++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Changelog/Comments.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs index 0655611230..cf8bac7642 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs @@ -24,6 +24,7 @@ namespace osu.Game.Tests.Visual.Online typeof(ChangelogListing), typeof(ChangelogSingleBuild), typeof(ChangelogBuild), + typeof(Comments), }; protected override void LoadComplete() diff --git a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs index 36407c7b0e..d11e2d454b 100644 --- a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs +++ b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs @@ -33,6 +33,8 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("versions")] public VersionNavigation Versions { get; set; } + public object Url => $"https://osu.ppy.sh/home/changelog/{UpdateStream.Name}/{Version}"; + public class VersionNavigation { [JsonProperty("next")] diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index 36ae5a756c..44552b214f 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -58,7 +58,11 @@ namespace osu.Game.Overlays.Changelog } if (build != null) - Child = new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }; + Children = new Drawable[] + { + new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, + new Comments(build) + }; } public class ChangelogBuildWithNavigation : ChangelogBuild diff --git a/osu.Game/Overlays/Changelog/Comments.cs b/osu.Game/Overlays/Changelog/Comments.cs new file mode 100644 index 0000000000..4cf39e7b44 --- /dev/null +++ b/osu.Game/Overlays/Changelog/Comments.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Changelog +{ + public class Comments : CompositeDrawable + { + private readonly APIChangelogBuild build; + + public Comments(APIChangelogBuild build) + { + this.build = build; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Padding = new MarginPadding + { + Horizontal = 50, + Vertical = 20, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + LinkFlowContainer text; + + InternalChildren = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 10, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.GreyVioletDarker + }, + }, + text = new LinkFlowContainer(t => + { + t.Colour = colours.PinkLighter; + t.Font = OsuFont.Default.With(size: 14); + }) + { + Padding = new MarginPadding(20), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + }; + + text.AddParagraph("Got feedback?", t => + { + t.Colour = Color4.White; + t.Font = OsuFont.Default.With(italics: true, size: 20); + t.Padding = new MarginPadding { Bottom = 20 }; + }); + + text.AddParagraph("We would love to hear what you think of this update! "); + text.AddIcon(FontAwesome.Regular.GrinHearts); + + text.AddParagraph("Please visit the "); + text.AddLink("web version", $"{build.Url}#comments"); + text.AddText(" of this changelog to leave any comments."); + } + } +} From 2b9f7d551f7214fba14b38f8629ba6b539700c4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 4 Jul 2019 16:16:17 +0900 Subject: [PATCH 20/44] Fix incorrect type specification --- osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs index d11e2d454b..56005e15f8 100644 --- a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs +++ b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs @@ -33,7 +33,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("versions")] public VersionNavigation Versions { get; set; } - public object Url => $"https://osu.ppy.sh/home/changelog/{UpdateStream.Name}/{Version}"; + public string Url => $"https://osu.ppy.sh/home/changelog/{UpdateStream.Name}/{Version}"; public class VersionNavigation { From 530675f3642a5da7729e9720276c4a4fe34c159e Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Jul 2019 17:05:29 +0900 Subject: [PATCH 21/44] Add tests as separate steps --- .../UserInterface/TestSceneButtonSystem.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs index 6c4d9b20f7..88129308db 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs @@ -43,25 +43,25 @@ namespace osu.Game.Tests.Visual.UserInterface buttons.SetOsuLogo(logo); foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType().Skip(1)) - AddStep($"State to {s}", () => - { - buttons.State = s; + AddStep($"State to {s}", () => buttons.State = s); - if (buttons.State == ButtonSystemState.EnteringMode) - { - buttons.FadeOut(400, Easing.InSine); - buttons.MoveTo(new Vector2(-800, 0), 400, Easing.InSine); - logo.FadeOut(300, Easing.InSine) - .ScaleTo(0.2f, 300, Easing.InSine); - } - else - { - buttons.FadeIn(400, Easing.OutQuint); - buttons.MoveTo(new Vector2(0), 400, Easing.OutQuint); - logo.FadeColour(Color4.White, 100, Easing.OutQuint); - logo.FadeIn(100, Easing.OutQuint); - } - }); + AddStep("Exiting menu", () => + { + buttons.State = ButtonSystemState.EnteringMode; + buttons.FadeOut(400, Easing.InSine); + buttons.MoveTo(new Vector2(-800, 0), 400, Easing.InSine); + logo.FadeOut(300, Easing.InSine) + .ScaleTo(0.2f, 300, Easing.InSine); + }); + + AddStep("Entering menu", () => + { + buttons.State = ButtonSystemState.Play; + buttons.FadeIn(400, Easing.OutQuint); + buttons.MoveTo(new Vector2(0), 400, Easing.OutQuint); + logo.FadeColour(Color4.White, 100, Easing.OutQuint); + logo.FadeIn(100, Easing.OutQuint); + }); } } } From 07078b735c7909fd192570d531bfd3a883312afb Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Jul 2019 17:06:28 +0900 Subject: [PATCH 22/44] use new vector2 --- osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs index e5a27dac81..88129308db 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Shapes; using osu.Game.Screens.Menu; +using osuTK; using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface From be4e7d0f5059ea1d5d6d00eea71c368207c6bc36 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Jul 2019 17:08:21 +0900 Subject: [PATCH 23/44] remove comment --- osu.Game/Screens/Menu/ButtonSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 040a9f8843..87c009c437 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -332,7 +332,6 @@ namespace osu.Game.Screens.Menu break; case ButtonSystemState.EnteringMode: - // When coming from the Initial (untracked) state, interpolate to the tracking position over a brief duration instead of tracking immediately. logoTrackingContainer.StartTracking(logo, lastState == ButtonSystemState.Initial ? 400 : 0, Easing.InSine); break; } From f04adb719252aaf723c89250aaf30e53c63e043d Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 3 Jul 2019 22:28:13 +0530 Subject: [PATCH 24/44] Apply mods filter to local scores too --- .../Select/Leaderboards/BeatmapLeaderboard.cs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 08f9632462..c1cbc40680 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -39,6 +39,9 @@ namespace osu.Game.Screens.Select.Leaderboards private bool filterMods; + /// + /// Whether to apply the game's currently selected mods as a filter when retrieving scores. + /// public bool FilterMods { get => filterMods; @@ -80,10 +83,25 @@ namespace osu.Game.Screens.Select.Leaderboards { if (Scope == BeatmapLeaderboardScope.Local) { - Scores = scoreManager - .QueryScores(s => !s.DeletePending && s.Beatmap.ID == Beatmap.ID && s.Ruleset.ID == ruleset.Value.ID) - .OrderByDescending(s => s.TotalScore).ToArray(); + var scores = scoreManager + .QueryScores(s => !s.DeletePending && s.Beatmap.ID == Beatmap.ID && s.Ruleset.ID == ruleset.Value.ID); + + if (filterMods && !mods.Value.Any()) + { + // we need to filter out all scores that have any mods to get all local nomod scores + scores = scores.Where(s => !s.Mods.Any()); + } + else if (filterMods) + { + // otherwise find all the scores that have *any* of the currently selected mods (similar to how web applies mod filters) + // we're creating and using a string list representation of selected mods so that it can be translated into the DB query itself + var selectedMods = mods.Value.Select(m => m.Acronym); + scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym))); + } + + Scores = scores.OrderByDescending(s => s.TotalScore).ToArray(); PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; + return null; } @@ -101,7 +119,7 @@ namespace osu.Game.Screens.Select.Leaderboards IReadOnlyList requestMods = null; - if (filterMods && mods.Value.Count == 0) + if (filterMods && !mods.Value.Any()) // add nomod for the request requestMods = new Mod[] { new ModNoMod() }; else if (filterMods) From bff5ad22f4fedf8c3a1c1ae9bb1e6cf791ed676e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 5 Jul 2019 05:16:40 +0300 Subject: [PATCH 25/44] Check if the locally available score has files --- osu.Game/Scoring/ScoreManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 2d82987da0..f0d897701c 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -65,6 +65,6 @@ namespace osu.Game.Scoring protected override ArchiveDownloadRequest CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score); - protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable items) => items.Any(s => s.OnlineScoreID == model.OnlineScoreID); + protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable items) => items.Any(s => s.OnlineScoreID == model.OnlineScoreID && s.Files.Any()); } } From d624157c45afc11187b58f523c8ff0e61d005c81 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 5 Jul 2019 05:17:36 +0300 Subject: [PATCH 26/44] Remove unnecessary fading --- osu.Game/Screens/Play/ReplayDownloadButton.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/ReplayDownloadButton.cs b/osu.Game/Screens/Play/ReplayDownloadButton.cs index 748fe8cc90..290e00f287 100644 --- a/osu.Game/Screens/Play/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Play/ReplayDownloadButton.cs @@ -86,11 +86,7 @@ namespace osu.Game.Screens.Play } }, true); - if (replayAvailability == ReplayAvailability.NotAvailable) - { - button.Enabled.Value = false; - button.Alpha = 0.6f; - } + button.Enabled.Value = replayAvailability != ReplayAvailability.NotAvailable; } private enum ReplayAvailability From 29bc2a27514a8573f17ebc1a9acf1e2e7813f003 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 11:29:47 +0900 Subject: [PATCH 27/44] Split out tests --- .../UserInterface/TestSceneButtonSystem.cs | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs index 88129308db..3b790d33b6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs @@ -24,11 +24,12 @@ namespace osu.Game.Tests.Visual.UserInterface typeof(Button) }; - public TestSceneButtonSystem() - { - OsuLogo logo; - ButtonSystem buttons; + private OsuLogo logo; + private ButtonSystem buttons; + [SetUp] + public void SetUp() => Schedule(() => + { Children = new Drawable[] { new Box @@ -37,15 +38,23 @@ namespace osu.Game.Tests.Visual.UserInterface RelativeSizeAxes = Axes.Both, }, buttons = new ButtonSystem(), - logo = new OsuLogo { RelativePositionAxes = Axes.Both } + logo = new OsuLogo + { + RelativePositionAxes = Axes.Both, + Position = new Vector2(0.5f) + } }; buttons.SetOsuLogo(logo); + }); + [Test] + public void TestAllStates() + { foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType().Skip(1)) AddStep($"State to {s}", () => buttons.State = s); - AddStep("Exiting menu", () => + AddStep("Enter mode", () => { buttons.State = ButtonSystemState.EnteringMode; buttons.FadeOut(400, Easing.InSine); @@ -54,7 +63,7 @@ namespace osu.Game.Tests.Visual.UserInterface .ScaleTo(0.2f, 300, Easing.InSine); }); - AddStep("Entering menu", () => + AddStep("Return to menu", () => { buttons.State = ButtonSystemState.Play; buttons.FadeIn(400, Easing.OutQuint); @@ -63,5 +72,18 @@ namespace osu.Game.Tests.Visual.UserInterface logo.FadeIn(100, Easing.OutQuint); }); } + + [Test] + public void TestSmoothExit() + { + AddStep("Enter mode", () => + { + buttons.State = ButtonSystemState.EnteringMode; + buttons.FadeOut(400, Easing.InSine); + buttons.MoveTo(new Vector2(-800, 0), 400, Easing.InSine); + logo.FadeOut(300, Easing.InSine) + .ScaleTo(0.2f, 300, Easing.InSine); + }); + } } } From a30f0c03bb071dbb4d959dc7da0c09ed4314ce51 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 5 Jul 2019 05:32:30 +0300 Subject: [PATCH 28/44] Fix incorrect xmldoc --- osu.Game/Online/DownloadTrackingComposite.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/DownloadTrackingComposite.cs b/osu.Game/Online/DownloadTrackingComposite.cs index 786afdf450..62d6efcb6f 100644 --- a/osu.Game/Online/DownloadTrackingComposite.cs +++ b/osu.Game/Online/DownloadTrackingComposite.cs @@ -11,7 +11,7 @@ using osu.Game.Online.API; namespace osu.Game.Online { /// - /// A component which tracks a beatmap through potential download/import/deletion. + /// A component which tracks a through potential download/import/deletion. /// public abstract class DownloadTrackingComposite : CompositeDrawable where TModel : class, IEquatable @@ -22,7 +22,7 @@ namespace osu.Game.Online private TModelManager manager; /// - /// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded. + /// Holds the current download state of the , whether is has already been downloaded, is in progress, or is not downloaded. /// protected readonly Bindable State = new Bindable(); From 1dab363be309abd7e94e57b161bd63ff74fb8af5 Mon Sep 17 00:00:00 2001 From: naoey Date: Fri, 5 Jul 2019 08:42:44 +0530 Subject: [PATCH 29/44] Require supporter for filtering mods on online leaderboards --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 88ce5dc117..76bfd96305 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -117,7 +117,7 @@ namespace osu.Game.Screens.Select.Leaderboards return null; } - if (Scope != BeatmapLeaderboardScope.Global && !api.LocalUser.Value.IsSupporter) + if (!api.LocalUser.Value.IsSupporter && (Scope != BeatmapLeaderboardScope.Global || filterMods)) { PlaceholderState = PlaceholderState.NotSupporter; return null; From f1dab946fff325ae420f87364a2636af4293316f Mon Sep 17 00:00:00 2001 From: naoey Date: Fri, 5 Jul 2019 08:46:17 +0530 Subject: [PATCH 30/44] Remove need to trim query string --- osu.Game/Online/API/Requests/GetScoresRequest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 53349e15d5..6b0e680eb5 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -50,13 +50,13 @@ namespace osu.Game.Online.API.Requests { StringBuilder query = new StringBuilder(@"?"); - query.Append($@"type={scope.ToString().ToLowerInvariant()}&"); - query.Append($@"mode={ruleset.ShortName}&"); + query.Append($@"type={scope.ToString().ToLowerInvariant()}"); + query.Append($@"&mode={ruleset.ShortName}"); foreach (var mod in mods) - query.Append($@"mods[]={mod.Acronym}&"); + query.Append($@"&mods[]={mod.Acronym}"); - return query.ToString().TrimEnd('&'); + return query.ToString(); } } } From 79d6670dc581ed27edaef31a0b57466fce707aeb Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Jul 2019 13:08:45 +0900 Subject: [PATCH 31/44] Expose durations from MainMenu and reorder --- .../UserInterface/TestSceneButtonSystem.cs | 8 ++++---- osu.Game/Screens/Menu/MainMenu.cs | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs index 88129308db..461db4a30c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs @@ -48,8 +48,8 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Exiting menu", () => { buttons.State = ButtonSystemState.EnteringMode; - buttons.FadeOut(400, Easing.InSine); - buttons.MoveTo(new Vector2(-800, 0), 400, Easing.InSine); + buttons.FadeOut(MainMenu.FADE_OUT_DURATION, Easing.InSine); + buttons.MoveTo(new Vector2(-800, 0), MainMenu.FADE_OUT_DURATION, Easing.InSine); logo.FadeOut(300, Easing.InSine) .ScaleTo(0.2f, 300, Easing.InSine); }); @@ -57,8 +57,8 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Entering menu", () => { buttons.State = ButtonSystemState.Play; - buttons.FadeIn(400, Easing.OutQuint); - buttons.MoveTo(new Vector2(0), 400, Easing.OutQuint); + buttons.FadeIn(MainMenu.FADE_IN_DURATION, Easing.OutQuint); + buttons.MoveTo(new Vector2(0), MainMenu.FADE_IN_DURATION, Easing.OutQuint); logo.FadeColour(Color4.White, 100, Easing.OutQuint); logo.FadeIn(100, Easing.OutQuint); }); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 7e6de54d1b..c64bea840f 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -23,7 +23,9 @@ namespace osu.Game.Screens.Menu { public class MainMenu : OsuScreen { - private ButtonSystem buttons; + public const float FADE_IN_DURATION = 300; + + public const float FADE_OUT_DURATION = 400; public override bool HideOverlaysOnEnter => buttons == null || buttons.State == ButtonSystemState.Initial; @@ -35,6 +37,8 @@ namespace osu.Game.Screens.Menu private MenuSideFlashes sideFlashes; + private ButtonSystem buttons; + [Resolved] private GameHost host { get; set; } @@ -141,12 +145,10 @@ namespace osu.Game.Screens.Menu { buttons.State = ButtonSystemState.TopLevel; - const float length = 300; + this.FadeIn(FADE_IN_DURATION, Easing.OutQuint); + this.MoveTo(new Vector2(0, 0), FADE_IN_DURATION, Easing.OutQuint); - this.FadeIn(length, Easing.OutQuint); - this.MoveTo(new Vector2(0, 0), length, Easing.OutQuint); - - sideFlashes.Delay(length).FadeIn(64, Easing.InQuint); + sideFlashes.Delay(FADE_IN_DURATION).FadeIn(64, Easing.InQuint); } } @@ -171,12 +173,10 @@ namespace osu.Game.Screens.Menu { base.OnSuspending(next); - const float length = 400; - buttons.State = ButtonSystemState.EnteringMode; - this.FadeOut(length, Easing.InSine); - this.MoveTo(new Vector2(-800, 0), length, Easing.InSine); + this.FadeOut(FADE_OUT_DURATION, Easing.InSine); + this.MoveTo(new Vector2(-800, 0), FADE_OUT_DURATION, Easing.InSine); sideFlashes.FadeOut(64, Easing.OutQuint); } From 4eb01b12be4f0cba9ec6a8aa8d17cabafb88284d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Jul 2019 13:10:59 +0900 Subject: [PATCH 32/44] Convert to method --- .../UserInterface/TestSceneButtonSystem.cs | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs index 9bc8f332f4..f0e1c38525 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs @@ -54,14 +54,7 @@ namespace osu.Game.Tests.Visual.UserInterface foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType().Skip(1)) AddStep($"State to {s}", () => buttons.State = s); - AddStep("Enter mode", () => - { - buttons.State = ButtonSystemState.EnteringMode; - buttons.FadeOut(MainMenu.FADE_OUT_DURATION, Easing.InSine); - buttons.MoveTo(new Vector2(-800, 0), MainMenu.FADE_OUT_DURATION, Easing.InSine); - logo.FadeOut(300, Easing.InSine) - .ScaleTo(0.2f, 300, Easing.InSine); - }); + AddStep("Enter mode", performEnterMode); AddStep("Return to menu", () => { @@ -76,14 +69,16 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestSmoothExit() { - AddStep("Enter mode", () => - { - buttons.State = ButtonSystemState.EnteringMode; - buttons.FadeOut(400, Easing.InSine); - buttons.MoveTo(new Vector2(-800, 0), 400, Easing.InSine); - logo.FadeOut(300, Easing.InSine) - .ScaleTo(0.2f, 300, Easing.InSine); - }); + AddStep("Enter mode", performEnterMode); + } + + private void performEnterMode() + { + buttons.State = ButtonSystemState.EnteringMode; + buttons.FadeOut(MainMenu.FADE_OUT_DURATION, Easing.InSine); + buttons.MoveTo(new Vector2(-800, 0), MainMenu.FADE_OUT_DURATION, Easing.InSine); + logo.FadeOut(300, Easing.InSine) + .ScaleTo(0.2f, 300, Easing.InSine); } } } From 8346c50ce113cdecea9378cf2a723795251c197b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 13:49:54 +0900 Subject: [PATCH 33/44] Rename delete method and improve xmldoc --- osu.Game/Beatmaps/BeatmapManager.cs | 4 +--- osu.Game/Database/ArchiveModelManager.cs | 8 +++++--- osu.Game/Skinning/SkinManager.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 643fef5904..df9c8973ea 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -82,9 +82,7 @@ namespace osu.Game.Beatmaps protected override ArchiveDownloadRequest CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) => new DownloadBeatmapSetRequest(set, minimiseDownloadSize); - protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); - - protected override bool ShouldRemoveArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz"; + protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osz"; protected override Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default) { diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 939333c6f4..dabd8fa2ef 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -176,7 +176,7 @@ namespace osu.Game.Database // TODO: Add a check to prevent files from storage to be deleted. try { - if (import != null && File.Exists(path) && ShouldRemoveArchive(path)) + if (import != null && File.Exists(path) && ShouldDeleteArchive(path)) File.Delete(path); } catch (Exception e) @@ -504,9 +504,11 @@ namespace osu.Game.Database protected abstract IEnumerable GetStableImportPaths(); /// - /// Should this archive be removed after importing? + /// Whether this specified path should be removed after successful import. /// - protected virtual bool ShouldRemoveArchive(string path) => false; + /// The path for consideration. May be a file or a directory. + /// Whether to perform deletion. + protected virtual bool ShouldDeleteArchive(string path) => false; /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 00e6fddc6a..3509263e6f 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -57,7 +57,7 @@ namespace osu.Game.Skinning protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); - protected override bool ShouldRemoveArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osk"; + protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osk"; /// /// Returns a list of all usable s. Includes the special default skin plus all skins from . From ba8df3ba9244034db85fa92828e19c7c9ce4c689 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 13:59:31 +0900 Subject: [PATCH 34/44] Clean up stable lookup and mutate logic --- osu.Game/Database/ArchiveModelManager.cs | 6 +++--- osu.Game/Scoring/ScoreManager.cs | 5 ++--- osu.Game/Skinning/SkinManager.cs | 2 -- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index dabd8fa2ef..445c8feb3b 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -486,7 +486,7 @@ namespace osu.Game.Database /// /// Set a storage with access to an osu-stable install for import purposes. /// - public Func GetStableStorage { protected get; set; } + public Func GetStableStorage { private get; set; } /// /// Denotes whether an osu-stable installation is present to perform automated imports from. @@ -501,7 +501,7 @@ namespace osu.Game.Database /// /// Selects paths to import from. /// - protected abstract IEnumerable GetStableImportPaths(); + protected virtual IEnumerable GetStableImportPaths(Storage stableStoage) => stableStoage.GetDirectories(ImportFromStablePath); /// /// Whether this specified path should be removed after successful import. @@ -530,7 +530,7 @@ namespace osu.Game.Database return Task.CompletedTask; } - return Task.Run(async () => await Import(GetStableImportPaths().Select(f => stable.GetFullPath(f)).ToArray())); + return Task.Run(async () => await Import(GetStableImportPaths(GetStableStorage()).Select(f => stable.GetFullPath(f)).ToArray())); } #endregion diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 4c7de90d6f..770b56e1fe 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -56,9 +56,8 @@ namespace osu.Game.Scoring } } - protected override IEnumerable GetStableImportPaths() - => GetStableStorage().GetFiles(ImportFromStablePath) - .Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.InvariantCultureIgnoreCase) ?? false)); + protected override IEnumerable GetStableImportPaths(Storage stableStorage) + => stableStorage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.InvariantCultureIgnoreCase) ?? false)); public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 3509263e6f..70abfac501 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -55,8 +55,6 @@ namespace osu.Game.Skinning }; } - protected override IEnumerable GetStableImportPaths() => GetStableStorage().GetDirectories(ImportFromStablePath); - protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == ".osk"; /// From 99da04527d5ca2b2e130acce60d1f5a1f831413d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 14:07:14 +0900 Subject: [PATCH 35/44] Replays -> scores --- .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index e3f5acc8ac..832673703b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Add(importScoresButton = new SettingsButton { - Text = "Import replays from stable", + Text = "Import scores from stable", Action = () => { importScoresButton.Enabled.Value = false; From 87c8fd0035ec6fa0b7cf37dbe10f674f695127ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 14:15:29 +0900 Subject: [PATCH 36/44] Fix path specification not being cross-platform compliant --- osu.Game/Scoring/ScoreManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 770b56e1fe..d78e9e073e 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -25,7 +25,7 @@ namespace osu.Game.Scoring protected override string[] HashableFileTypes => new[] { ".osr" }; - protected override string ImportFromStablePath => @"Data\r"; + protected override string ImportFromStablePath => Path.Combine("Data", "r"); private readonly RulesetStore rulesets; private readonly Func beatmaps; From 80d8ce83928a09042fd52c5d985fc051d836445f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 14:21:56 +0900 Subject: [PATCH 37/44] Fix GetStableImportPaths xmldoc --- osu.Game/Database/ArchiveModelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 445c8feb3b..355411063d 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -499,7 +499,7 @@ namespace osu.Game.Database protected virtual string ImportFromStablePath => null; /// - /// Selects paths to import from. + /// Select paths to import from stable. Default implementation iterates all directories in . /// protected virtual IEnumerable GetStableImportPaths(Storage stableStoage) => stableStoage.GetDirectories(ImportFromStablePath); From adf6d6c942b2c32c4522458c0023fb89da32915c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 14:25:52 +0900 Subject: [PATCH 38/44] Update initial run import process to include scores --- osu.Game/Screens/Select/ImportFromStablePopup.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/ImportFromStablePopup.cs b/osu.Game/Screens/Select/ImportFromStablePopup.cs index 54e4c096f6..20494829ae 100644 --- a/osu.Game/Screens/Select/ImportFromStablePopup.cs +++ b/osu.Game/Screens/Select/ImportFromStablePopup.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Select public ImportFromStablePopup(Action importFromStable) { HeaderText = @"You have no beatmaps!"; - BodyText = "An existing copy of osu! was found, though.\nWould you like to import your beatmaps (and skins)?"; + BodyText = "An existing copy of osu! was found, though.\nWould you like to import your beatmaps, skins and scores?"; Icon = FontAwesome.Solid.Plane; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 3581ed5534..bf5857f725 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -35,6 +35,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; +using osu.Game.Scoring; namespace osu.Game.Screens.Select { @@ -215,7 +216,7 @@ namespace osu.Game.Screens.Select } [BackgroundDependencyLoader(true)] - private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours, SkinManager skins) + private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours, SkinManager skins, ScoreManager scores) { mods.BindTo(Mods); @@ -252,7 +253,7 @@ namespace osu.Game.Screens.Select if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable) dialogOverlay.Push(new ImportFromStablePopup(() => { - Task.Run(beatmaps.ImportFromStableAsync); + Task.Run(beatmaps.ImportFromStableAsync).ContinueWith(_ => scores.ImportFromStableAsync(), TaskContinuationOptions.OnlyOnRanToCompletion); Task.Run(skins.ImportFromStableAsync); })); }); From df7d31350c8fe8e22478d88f5a57da0b83d88a30 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 14:47:55 +0900 Subject: [PATCH 39/44] Stop import failures from being added to the imported model list --- osu.Game/Database/ArchiveModelManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 01455e7d50..7d81b95203 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -114,7 +114,8 @@ namespace osu.Game.Database lock (imported) { - imported.Add(model); + if (model != null) + imported.Add(model); current++; notification.Text = $"Imported {current} of {paths.Length} {HumanisedModelName}s"; @@ -140,7 +141,7 @@ namespace osu.Game.Database { notification.CompletionText = imported.Count == 1 ? $"Imported {imported.First()}!" - : $"Imported {current} {HumanisedModelName}s!"; + : $"Imported {imported.Count} {HumanisedModelName}s!"; if (imported.Count > 0 && PresentImport != null) { From b902457f8dbe8609b679cdbdfce50cfba3d113d1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 15:32:07 +0900 Subject: [PATCH 40/44] Allow PlayerLoader to proceed even if the mouse is hovering an overlay panel --- osu.Game/Screens/Play/PlayerLoader.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 681ce701d0..5396321160 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -18,6 +18,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Input; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Menu; using osu.Game.Screens.Play.HUD; @@ -53,6 +54,8 @@ namespace osu.Game.Screens.Play private InputManager inputManager; + private IdleTracker idleTracker; + public PlayerLoader(Func createPlayer) { this.createPlayer = createPlayer; @@ -93,7 +96,8 @@ namespace osu.Game.Screens.Play VisualSettings = new VisualSettings(), new InputSettings() } - } + }, + idleTracker = new IdleTracker(750) }); loadNewPlayer(); @@ -193,7 +197,7 @@ namespace osu.Game.Screens.Play // Here because IsHovered will not update unless we do so. public override bool HandlePositionalInput => true; - private bool readyForPush => player.LoadState == LoadState.Ready && IsHovered && GetContainingInputManager()?.DraggedDrawable == null; + private bool readyForPush => player.LoadState == LoadState.Ready && (IsHovered || idleTracker.IsIdle.Value) && inputManager?.DraggedDrawable == null; private void pushWhenLoaded() { From 39bd5e6478daefc5369c34c89ba30bceab73716c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Jul 2019 15:50:31 +0900 Subject: [PATCH 41/44] Add test --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index daee3a520c..18edaf1b92 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -9,6 +9,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.MathUtils; using osu.Framework.Screens; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -16,12 +17,13 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.PlayerSettings; namespace osu.Game.Tests.Visual.Gameplay { public class TestScenePlayerLoader : ManualInputManagerTestScene { - private PlayerLoader loader; + private TestPlayerLoader loader; private OsuScreenStack stack; [SetUp] @@ -31,19 +33,28 @@ namespace osu.Game.Tests.Visual.Gameplay Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); }); + [Test] + public void TestBlockLoadViaMouseMovement() + { + AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false)))); + AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20); + AddAssert("loader still active", () => loader.IsCurrentScreen()); + AddUntilStep("loads after idle", () => !loader.IsCurrentScreen()); + } + [Test] public void TestLoadContinuation() { Player player = null; SlowLoadPlayer slowPlayer = null; - AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => player = new TestPlayer(false, false)))); + AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer(false, false)))); AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); AddUntilStep("wait for player to be current", () => player.IsCurrentScreen()); AddStep("load slow dummy beatmap", () => { - stack.Push(loader = new PlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + stack.Push(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000); }); @@ -61,7 +72,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("load player", () => { Mods.Value = new[] { gameMod = new TestMod() }; - stack.Push(loader = new PlayerLoader(() => player = new TestPlayer())); + stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer())); }); AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen()); @@ -85,6 +96,16 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("player mods applied", () => playerMod2.Applied); } + private class TestPlayerLoader : PlayerLoader + { + public new VisualSettings VisualSettings => base.VisualSettings; + + public TestPlayerLoader(Func createPlayer) + : base(createPlayer) + { + } + } + private class TestMod : Mod, IApplicableToScoreProcessor { public override string Name => string.Empty; From a259247a98fa40d4beb3db268032225533df2e34 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Jul 2019 16:07:17 +0900 Subject: [PATCH 42/44] use const --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 87c009c437..1a3e1213b4 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -332,7 +332,7 @@ namespace osu.Game.Screens.Menu break; case ButtonSystemState.EnteringMode: - logoTrackingContainer.StartTracking(logo, lastState == ButtonSystemState.Initial ? 400 : 0, Easing.InSine); + logoTrackingContainer.StartTracking(logo, lastState == ButtonSystemState.Initial ? MainMenu.FADE_OUT_DURATION : 0, Easing.InSine); break; } } From 64de3840b0f84f805077d7434b30e4295372e922 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 6 Jul 2019 15:25:53 +0900 Subject: [PATCH 43/44] Add missing wait step in TestScenePlayerLoader --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 18edaf1b92..ab519360ac 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -37,6 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestBlockLoadViaMouseMovement() { AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false)))); + AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20); AddAssert("loader still active", () => loader.IsCurrentScreen()); AddUntilStep("loads after idle", () => !loader.IsCurrentScreen()); From 6fd3ad5c1dac275e6a8112f4ae8af31f64ee99f4 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sat, 6 Jul 2019 12:10:30 +0300 Subject: [PATCH 44/44] Remove unnecessary fading --- .../Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs index 1fd3502799..30346a8a96 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs @@ -35,15 +35,15 @@ namespace osu.Game.Beatmaps.Drawables protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Func createContentFunc, double timeBeforeLoad) => new DelayedLoadUnloadWrapper(createContentFunc, timeBeforeLoad, UnloadDelay); + protected override double TransformDuration => 400; + protected override Drawable CreateDrawable(BeatmapInfo model) { - Drawable drawable = getDrawableForModel(model); - + var drawable = getDrawableForModel(model); drawable.RelativeSizeAxes = Axes.Both; drawable.Anchor = Anchor.Centre; drawable.Origin = Anchor.Centre; drawable.FillMode = FillMode.Fill; - drawable.OnLoadComplete += d => d.FadeInFromZero(400); return drawable; }