From ed679846388c4d6104cf7b5f527ddc38d1ce3ff3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Nov 2018 13:06:48 +0900 Subject: [PATCH 01/11] Don't load player if score has no replay data --- osu.Game/OsuGame.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index eeeb24d7d4..a373be32a9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -267,15 +267,17 @@ namespace osu.Game return; } - var databasedBeatmap = BeatmapManager.QueryBeatmap(b => b.ID == score.Beatmap.ID); + var score = ScoreManager.GetScore(scoreInfo); + if (score.Replay == null) + { + Logger.Log("The loaded score has no replay data.", LoggingTarget.Information); + return; + } + var databasedBeatmap = BeatmapManager.QueryBeatmap(b => b.ID == scoreInfo.BeatmapInfo.ID); if (databasedBeatmap == null) { - notifications.Post(new SimpleNotification - { - Text = @"Tried to load a score for a beatmap we don't have!", - Icon = FontAwesome.fa_life_saver, - }); + Logger.Log("Tried to load a score for a beatmap we don't have!", LoggingTarget.Information); return; } @@ -284,7 +286,7 @@ namespace osu.Game Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); Beatmap.Value.Mods.Value = score.Mods; - menu.Push(new PlayerLoader(new ReplayPlayer(ScoreManager.GetScore(score).Replay))); + menu.Push(new PlayerLoader(new ReplayPlayer(score.Replay))); } protected override void Dispose(bool isDisposing) From 8eff49bccdabc3c345bb4f23244f69fb51c4eedb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Nov 2018 13:22:45 +0900 Subject: [PATCH 02/11] Remove User from Replay --- .../Replays/CatchAutoGenerator.cs | 3 +-- .../Replays/ManiaAutoGenerator.cs | 3 +-- osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs | 2 ++ .../Replays/OsuAutoGeneratorBase.cs | 9 +------- .../Replays/TaikoAutoGenerator.cs | 9 +------- osu.Game.Tests/Visual/TestCaseReplay.cs | 6 ++--- osu.Game/OsuGame.cs | 2 +- osu.Game/Replays/Replay.cs | 2 -- osu.Game/Scoring/Legacy/LegacyScoreParser.cs | 2 +- osu.Game/Screens/Play/Player.cs | 23 ++++++++++++------- osu.Game/Screens/Play/ReplayPlayer.cs | 12 ++++++---- 11 files changed, 32 insertions(+), 41 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs index b0376b547d..20bf2ee5c7 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs @@ -9,7 +9,6 @@ using osu.Game.Replays; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Replays; -using osu.Game.Users; namespace osu.Game.Rulesets.Catch.Replays { @@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Replays public CatchAutoGenerator(Beatmap beatmap) : base(beatmap) { - Replay = new Replay { User = new User { Username = @"Autoplay" } }; + Replay = new Replay(); } protected Replay Replay; diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 52672e6f17..c58d66c66a 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -8,7 +8,6 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; -using osu.Game.Users; namespace osu.Game.Rulesets.Mania.Replays { @@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Replays public ManiaAutoGenerator(ManiaBeatmap beatmap) : base(beatmap) { - Replay = new Replay { User = new User { Username = @"Autoplay" } }; + Replay = new Replay(); columnActions = new ManiaAction[Beatmap.TotalColumns]; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs index ce5d3dae44..7ef01e075c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Scoring; +using osu.Game.Users; namespace osu.Game.Rulesets.Osu.Mods { @@ -17,6 +18,7 @@ namespace osu.Game.Rulesets.Osu.Mods protected override Score CreateReplayScore(Beatmap beatmap) => new Score { + ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } }, Replay = new OsuAutoGenerator(beatmap).Generate() }; } diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 12d130ef53..6dc5e42258 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using osu.Game.Replays; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Replays; -using osu.Game.Users; namespace osu.Game.Rulesets.Osu.Replays { @@ -38,13 +37,7 @@ namespace osu.Game.Rulesets.Osu.Replays protected OsuAutoGeneratorBase(Beatmap beatmap) : base(beatmap) { - Replay = new Replay - { - User = new User - { - Username = @"Autoplay", - } - }; + Replay = new Replay(); // We are using ApplyModsToRate and not ApplyModsToTime to counteract the speed up / slow down from HalfTime / DoubleTime so that we remain at a constant framerate of 60 fps. FrameDelay = ApplyModsToRate(1000.0 / 60.0); diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index f089877f38..2794a3c166 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -9,7 +9,6 @@ using osu.Game.Replays; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Replays; -using osu.Game.Users; namespace osu.Game.Rulesets.Taiko.Replays { @@ -20,13 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Replays public TaikoAutoGenerator(Beatmap beatmap) : base(beatmap) { - Replay = new Replay - { - User = new User - { - Username = @"Autoplay", - } - }; + Replay = new Replay(); } protected Replay Replay; diff --git a/osu.Game.Tests/Visual/TestCaseReplay.cs b/osu.Game.Tests/Visual/TestCaseReplay.cs index 1f2d99a7d8..e0ea613534 100644 --- a/osu.Game.Tests/Visual/TestCaseReplay.cs +++ b/osu.Game.Tests/Visual/TestCaseReplay.cs @@ -5,6 +5,7 @@ using System.ComponentModel; using System.Linq; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Scoring; using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual @@ -19,13 +20,10 @@ namespace osu.Game.Tests.Visual Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(Beatmap.Value); - // We have the replay - var replay = dummyRulesetContainer.Replay; - // Reset the mods Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Where(m => !(m is ModAutoplay)); - return new ReplayPlayer(replay); + return new ReplayPlayer(new Score { Replay = dummyRulesetContainer.Replay }); } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a373be32a9..302509423f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -286,7 +286,7 @@ namespace osu.Game Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); Beatmap.Value.Mods.Value = score.Mods; - menu.Push(new PlayerLoader(new ReplayPlayer(score.Replay))); + menu.Push(new PlayerLoader(new ReplayPlayer(score))); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Replays/Replay.cs b/osu.Game/Replays/Replay.cs index 966849c783..bb6d9e7637 100644 --- a/osu.Game/Replays/Replay.cs +++ b/osu.Game/Replays/Replay.cs @@ -3,13 +3,11 @@ using System.Collections.Generic; using osu.Game.Rulesets.Replays; -using osu.Game.Users; namespace osu.Game.Replays { public class Replay { - public User User; public List Frames = new List(); } } diff --git a/osu.Game/Scoring/Legacy/LegacyScoreParser.cs b/osu.Game/Scoring/Legacy/LegacyScoreParser.cs index 7fc0d97f9b..13fe021f95 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreParser.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreParser.cs @@ -45,7 +45,7 @@ namespace osu.Game.Scoring.Legacy currentBeatmap = workingBeatmap.Beatmap; score.ScoreInfo.Beatmap = currentBeatmap.BeatmapInfo; - score.ScoreInfo.User = score.Replay.User = new User { Username = sr.ReadString() }; + score.ScoreInfo.User = new User { Username = sr.ReadString() }; // MD5Hash sr.ReadString(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 24592ebedc..e10bd1fd69 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -273,20 +273,27 @@ namespace osu.Game.Screens.Play { if (!IsCurrentScreen) return; - var score = new ScoreInfo - { - Beatmap = Beatmap.Value.BeatmapInfo, - Ruleset = ruleset - }; - ScoreProcessor.PopulateScore(score); - score.User = RulesetContainer.Replay?.User ?? api.LocalUser.Value; - Push(new Results(score)); + Push(new Results(CreateScoreInfo())); onCompletionEvent = null; }); } } + protected virtual ScoreInfo CreateScoreInfo() + { + var score = new ScoreInfo + { + BeatmapInfo = Beatmap.Value.BeatmapInfo, + Ruleset = ruleset, + User = api.LocalUser.Value + }; + + ScoreProcessor.PopulateScore(score); + + return score; + } + private bool onFail() { if (Beatmap.Value.Mods.Value.OfType().Any(m => !m.AllowFail)) diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 9204a49ac9..508933052a 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -1,23 +1,25 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Replays; +using osu.Game.Scoring; namespace osu.Game.Screens.Play { public class ReplayPlayer : Player { - public Replay Replay; + private readonly Score score; - public ReplayPlayer(Replay replay) + public ReplayPlayer(Score score) { - Replay = replay; + this.score = score; } protected override void LoadComplete() { base.LoadComplete(); - RulesetContainer.SetReplay(Replay); + RulesetContainer.SetReplay(score.Replay); } + + protected override ScoreInfo CreateScoreInfo() => score.ScoreInfo; } } From 4c1abdcd8c82f07ca51ec0d27963592c7af96fa9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Nov 2018 14:56:29 +0900 Subject: [PATCH 03/11] Save score upon map completion --- osu.Game/Screens/Play/Player.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e10bd1fd69..c44fba0c69 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -67,6 +67,9 @@ namespace osu.Game.Screens.Play /// private DecoupleableInterpolatingFramedClock adjustableClock; + [Resolved] + private ScoreManager scoreManager { get; set; } + private PauseContainer pauseContainer; private RulesetInfo ruleset; @@ -273,7 +276,11 @@ namespace osu.Game.Screens.Play { if (!IsCurrentScreen) return; - Push(new Results(CreateScoreInfo())); + var score = CreateScoreInfo(); + if (RulesetContainer.Replay == null) + scoreManager.Import(score); + + Push(new Results(score)); onCompletionEvent = null; }); From d07a724970672a2f847253b41363c53f86f37b85 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Nov 2018 17:18:59 +0900 Subject: [PATCH 04/11] Only allow replay screen changes in menu + songselect --- osu.Game/OsuGame.cs | 48 +++++++++++++++++++-------- osu.Game/Screens/Menu/MainMenu.cs | 2 ++ osu.Game/Screens/OsuScreen.cs | 2 ++ osu.Game/Screens/Select/SongSelect.cs | 2 ++ 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 302509423f..26e587e5dd 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -260,13 +260,6 @@ namespace osu.Game return; } - if (!menu.IsCurrentScreen) - { - menu.MakeCurrent(); - this.Delay(500).Schedule(() => LoadScore(score), out scoreLoad); - return; - } - var score = ScoreManager.GetScore(scoreInfo); if (score.Replay == null) { @@ -274,19 +267,46 @@ namespace osu.Game return; } - var databasedBeatmap = BeatmapManager.QueryBeatmap(b => b.ID == scoreInfo.BeatmapInfo.ID); - if (databasedBeatmap == null) + if (!currentScreen.AllowExternalScreenChange) { - Logger.Log("Tried to load a score for a beatmap we don't have!", LoggingTarget.Information); + notifications.Post(new SimpleNotification + { + Text = $"Click here to watch {scoreInfo.User.Username} on {scoreInfo.BeatmapInfo}", + Activated = () => + { + loadScore(); + return true; + } + }); + return; } - ruleset.Value = score.Ruleset; + loadScore(); - Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); - Beatmap.Value.Mods.Value = score.Mods; + void loadScore() + { + if (!menu.IsCurrentScreen) + { + menu.MakeCurrent(); + this.Delay(500).Schedule(loadScore, out scoreLoad); + return; + } - menu.Push(new PlayerLoader(new ReplayPlayer(score))); + var databasedBeatmap = BeatmapManager.QueryBeatmap(b => b.ID == scoreInfo.BeatmapInfo.ID); + if (databasedBeatmap == null) + { + Logger.Log("Tried to load a score for a beatmap we don't have!", LoggingTarget.Information); + return; + } + + ruleset.Value = score.Ruleset; + + Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); + Beatmap.Value.Mods.Value = score.Mods; + + currentScreen.Push(new PlayerLoader(new ReplayPlayer(score))); + } } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index cafd718055..974e42dda0 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -29,6 +29,8 @@ namespace osu.Game.Screens.Menu protected override bool AllowBackButton => buttons.State != ButtonSystemState.Initial; + public override bool AllowExternalScreenChange => true; + private readonly BackgroundScreenDefault background; private Screen songSelect; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 00309fbcd5..69f2b6ef9d 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -34,6 +34,8 @@ namespace osu.Game.Screens protected virtual bool AllowBackButton => true; + public virtual bool AllowExternalScreenChange => false; + /// /// Override to create a BackgroundMode for the current screen. /// Note that the instance created may not be the used instance if it matches the BackgroundMode equality clause. diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 360032c37c..b8458c4c70 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -40,6 +40,8 @@ namespace osu.Game.Screens.Select protected virtual bool ShowFooter => true; + public override bool AllowExternalScreenChange => true; + /// /// Can be null if is false. /// From a8ad7d4670723e9f9e8a454fe0d88bed9f42faee Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Nov 2018 18:07:51 +0900 Subject: [PATCH 05/11] Add silent import parameter --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 +- osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs | 2 +- osu.Game/Database/ArchiveModelManager.cs | 13 +++++++------ osu.Game/Database/MutableDatabaseBackedStore.cs | 13 ++++++++----- osu.Game/OsuGame.cs | 9 ++++++--- osu.Game/Overlays/Direct/DirectPanel.cs | 2 +- osu.Game/Overlays/Music/PlaylistList.cs | 4 ++-- osu.Game/Overlays/MusicController.cs | 2 +- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 11 files changed, 30 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index fb6f735d2d..26167cb24a 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Beatmaps.IO int fireCount = 0; // ReSharper disable once AccessToModifiedClosure - manager.ItemAdded += (_, __) => fireCount++; + manager.ItemAdded += (_, __, ___) => fireCount++; manager.ItemRemoved += _ => fireCount++; var imported = loadOszIntoOsu(osu); diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs index f1920b43cc..baeeaf81a4 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs @@ -78,7 +78,7 @@ namespace osu.Game.Beatmaps.Drawables } } - private void setAdded(BeatmapSetInfo s, bool existing) => Schedule(() => + private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => Schedule(() => { if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID) DownloadState.Value = DownloadStatus.Downloaded; diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index a7c2aad260..b870b7dfc2 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -32,7 +32,7 @@ namespace osu.Game.Database where TModel : class, IHasFiles, IHasPrimaryKey, ISoftDelete where TFileModel : INamedFileInfo, new() { - public delegate void ItemAddedDelegate(TModel model, bool existing); + public delegate void ItemAddedDelegate(TModel model, bool existing, bool silent); /// /// Set an endpoint for notifications to be posted to. @@ -110,7 +110,7 @@ namespace osu.Game.Database ContextFactory = contextFactory; ModelStore = modelStore; - ModelStore.ItemAdded += s => handleEvent(() => ItemAdded?.Invoke(s, false)); + ModelStore.ItemAdded += (item, silent) => handleEvent(() => ItemAdded?.Invoke(item, false, silent)); ModelStore.ItemRemoved += s => handleEvent(() => ItemRemoved?.Invoke(s)); Files = new FileStore(contextFactory, storage); @@ -211,7 +211,7 @@ namespace osu.Game.Database model.Hash = computeHash(archive); - return Import(model, archive); + return Import(model, false, archive); } catch (Exception e) { @@ -245,8 +245,9 @@ namespace osu.Game.Database /// Import an item from a . /// /// The model to be imported. + /// Whether the user should be notified fo the import. /// An optional archive to use for model population. - public TModel Import(TModel item, ArchiveReader archive = null) + public TModel Import(TModel item, bool silent = false, ArchiveReader archive = null) { delayEvents(); @@ -266,7 +267,7 @@ namespace osu.Game.Database { Undelete(existing); Logger.Log($"Found existing {typeof(TModel)} for {item} (ID {existing.ID}). Skipping import.", LoggingTarget.Database); - handleEvent(() => ItemAdded?.Invoke(existing, true)); + handleEvent(() => ItemAdded?.Invoke(existing, true, silent)); return existing; } @@ -276,7 +277,7 @@ namespace osu.Game.Database Populate(item, archive); // import to store - ModelStore.Add(item); + ModelStore.Add(item, silent); } catch (Exception e) { diff --git a/osu.Game/Database/MutableDatabaseBackedStore.cs b/osu.Game/Database/MutableDatabaseBackedStore.cs index 69a1f57cc4..dc2fe54aac 100644 --- a/osu.Game/Database/MutableDatabaseBackedStore.cs +++ b/osu.Game/Database/MutableDatabaseBackedStore.cs @@ -16,7 +16,9 @@ namespace osu.Game.Database public abstract class MutableDatabaseBackedStore : DatabaseBackedStore where T : class, IHasPrimaryKey, ISoftDelete { - public event Action ItemAdded; + public delegate void ItemAddedDelegate(T model, bool silent); + + public event ItemAddedDelegate ItemAdded; public event Action ItemRemoved; protected MutableDatabaseBackedStore(IDatabaseContextFactory contextFactory, Storage storage = null) @@ -33,7 +35,8 @@ namespace osu.Game.Database /// Add a to the database. /// /// The item to add. - public void Add(T item) + /// Whether the user should be notified of the addition. + public void Add(T item, bool silent) { using (var usage = ContextFactory.GetForWrite()) { @@ -41,7 +44,7 @@ namespace osu.Game.Database context.Attach(item); } - ItemAdded?.Invoke(item); + ItemAdded?.Invoke(item, silent); } /// @@ -54,7 +57,7 @@ namespace osu.Game.Database usage.Context.Update(item); ItemRemoved?.Invoke(item); - ItemAdded?.Invoke(item); + ItemAdded?.Invoke(item, true); } /// @@ -89,7 +92,7 @@ namespace osu.Game.Database item.DeletePending = false; } - ItemAdded?.Invoke(item); + ItemAdded?.Invoke(item, true); return true; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 26e587e5dd..03ddc8da86 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -148,7 +148,7 @@ namespace osu.Game { this.frameworkConfig = frameworkConfig; - ScoreManager.ItemAdded += (score, _) => Schedule(() => LoadScore(score)); + ScoreManager.ItemAdded += (score, _, silent) => Schedule(() => LoadScore(score, silent)); if (!Host.IsPrimaryInstance) { @@ -248,15 +248,18 @@ namespace osu.Game /// The beatmap to show. public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId); - protected void LoadScore(ScoreInfo score) + protected void LoadScore(ScoreInfo score, bool silent) { + if (silent) + return; + scoreLoad?.Cancel(); var menu = intro.ChildScreen; if (menu == null) { - scoreLoad = Schedule(() => LoadScore(score)); + scoreLoad = Schedule(() => LoadScore(score, false)); return; } diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 5b98d92654..44556a6360 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -174,7 +174,7 @@ namespace osu.Game.Overlays.Direct }; } - private void setAdded(BeatmapSetInfo s, bool existing) => Schedule(() => + private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => Schedule(() => { if (s.OnlineBeatmapSetID == SetInfo.OnlineBeatmapSetID) progressBar.FadeOut(500); diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index a2a835a259..b619abbc2f 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Music [BackgroundDependencyLoader] private void load(BeatmapManager beatmaps, IBindableBeatmap beatmap) { - beatmaps.GetAllUsableBeatmapSets().ForEach(b => addBeatmapSet(b, false)); + beatmaps.GetAllUsableBeatmapSets().ForEach(b => addBeatmapSet(b, false, false)); beatmaps.ItemAdded += addBeatmapSet; beatmaps.ItemRemoved += removeBeatmapSet; @@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Music beatmapBacking.ValueChanged += _ => updateSelectedSet(); } - private void addBeatmapSet(BeatmapSetInfo obj, bool existing) => Schedule(() => + private void addBeatmapSet(BeatmapSetInfo obj, bool existing, bool silent) => Schedule(() => { if (existing) return; diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 31fceebc93..2dc997d5ed 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -214,7 +214,7 @@ namespace osu.Game.Overlays beatmapSets.Insert(index, beatmapSetInfo); } - private void handleBeatmapAdded(BeatmapSetInfo obj, bool existing) + private void handleBeatmapAdded(BeatmapSetInfo obj, bool existing, bool silent) { if (existing) return; diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index e03bf856c9..23f35d5d3a 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -72,7 +72,7 @@ namespace osu.Game.Overlays.Settings.Sections private void itemRemoved(SkinInfo s) => Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != s.ID).ToArray()); - private void itemAdded(SkinInfo s, bool existing) + private void itemAdded(SkinInfo s, bool existing, bool silent) { if (existing) return; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c44fba0c69..136f015080 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -278,7 +278,7 @@ namespace osu.Game.Screens.Play var score = CreateScoreInfo(); if (RulesetContainer.Replay == null) - scoreManager.Import(score); + scoreManager.Import(score, true); Push(new Results(score)); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b8458c4c70..f4af4f9068 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -505,7 +505,7 @@ namespace osu.Game.Screens.Select } } - private void onBeatmapSetAdded(BeatmapSetInfo s, bool existing) => Carousel.UpdateBeatmapSet(s); + private void onBeatmapSetAdded(BeatmapSetInfo s, bool existing, bool silent) => Carousel.UpdateBeatmapSet(s); private void onBeatmapSetRemoved(BeatmapSetInfo s) => Carousel.RemoveBeatmapSet(s); private void onBeatmapRestored(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); private void onBeatmapHidden(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); From a6b0e35b2d5252416bd0fac48fd9d4f1521634bf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Nov 2018 18:31:54 +0900 Subject: [PATCH 06/11] Fix post-rebase issues --- osu.Game/OsuGame.cs | 27 ++++++++++++++------------- osu.Game/Screens/Play/Player.cs | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 03ddc8da86..cd40d4793a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -263,18 +263,26 @@ namespace osu.Game return; } - var score = ScoreManager.GetScore(scoreInfo); - if (score.Replay == null) + var databasedScore = ScoreManager.GetScore(score); + var databasedScoreInfo = databasedScore.ScoreInfo; + if (databasedScore.Replay == null) { Logger.Log("The loaded score has no replay data.", LoggingTarget.Information); return; } + var databasedBeatmap = BeatmapManager.QueryBeatmap(b => b.ID == databasedScoreInfo.Beatmap.ID); + if (databasedBeatmap == null) + { + Logger.Log("Tried to load a score for a beatmap we don't have!", LoggingTarget.Information); + return; + } + if (!currentScreen.AllowExternalScreenChange) { notifications.Post(new SimpleNotification { - Text = $"Click here to watch {scoreInfo.User.Username} on {scoreInfo.BeatmapInfo}", + Text = $"Click here to watch {databasedScoreInfo.User.Username} on {databasedScoreInfo.Beatmap}", Activated = () => { loadScore(); @@ -296,19 +304,12 @@ namespace osu.Game return; } - var databasedBeatmap = BeatmapManager.QueryBeatmap(b => b.ID == scoreInfo.BeatmapInfo.ID); - if (databasedBeatmap == null) - { - Logger.Log("Tried to load a score for a beatmap we don't have!", LoggingTarget.Information); - return; - } - - ruleset.Value = score.Ruleset; + ruleset.Value = databasedScoreInfo.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); - Beatmap.Value.Mods.Value = score.Mods; + Beatmap.Value.Mods.Value = databasedScoreInfo.Mods; - currentScreen.Push(new PlayerLoader(new ReplayPlayer(score))); + currentScreen.Push(new PlayerLoader(new ReplayPlayer(databasedScore))); } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 136f015080..01721775a0 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -291,7 +291,7 @@ namespace osu.Game.Screens.Play { var score = new ScoreInfo { - BeatmapInfo = Beatmap.Value.BeatmapInfo, + Beatmap = Beatmap.Value.BeatmapInfo, Ruleset = ruleset, User = api.LocalUser.Value }; From 795933d1a1c52e6749f39a87374abd0dadd7f3ee Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Nov 2018 18:32:08 +0900 Subject: [PATCH 07/11] CreateScoreInfo -> CreateScore --- osu.Game/Screens/Play/Player.cs | 4 ++-- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 01721775a0..bf44e9e636 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -276,7 +276,7 @@ namespace osu.Game.Screens.Play { if (!IsCurrentScreen) return; - var score = CreateScoreInfo(); + var score = CreateScore(); if (RulesetContainer.Replay == null) scoreManager.Import(score, true); @@ -287,7 +287,7 @@ namespace osu.Game.Screens.Play } } - protected virtual ScoreInfo CreateScoreInfo() + protected virtual ScoreInfo CreateScore() { var score = new ScoreInfo { diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 508933052a..fe77fd57f2 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -20,6 +20,6 @@ namespace osu.Game.Screens.Play RulesetContainer.SetReplay(score.Replay); } - protected override ScoreInfo CreateScoreInfo() => score.ScoreInfo; + protected override ScoreInfo CreateScore() => score.ScoreInfo; } } From 4144f4bd2f2ab8447cef37dfa71f24a3965bbd24 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Nov 2018 18:40:06 +0900 Subject: [PATCH 08/11] Fix duplicates not being ignored if hash is null --- 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 b870b7dfc2..50767608af 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -508,7 +508,7 @@ namespace osu.Game.Database /// /// The new model proposed for import. Note that has not yet been run on this model. /// An existing model which matches the criteria to skip importing, else null. - protected virtual TModel CheckForExisting(TModel model) => ModelStore.ConsumableItems.FirstOrDefault(b => b.Hash == model.Hash); + protected virtual TModel CheckForExisting(TModel model) => model.Hash == null ? null : ModelStore.ConsumableItems.FirstOrDefault(b => b.Hash == model.Hash); private DbSet queryModel() => ContextFactory.Get().Set(); From 10ed09521cd6795f2724d179a14f07f170256efc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 29 Nov 2018 18:30:43 +0900 Subject: [PATCH 09/11] Add leaderboard display for local scores --- osu.Game/Scoring/ScoreManager.cs | 2 ++ osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 9 +++++++-- osu.Game/Screens/Select/PlaySongSelect.cs | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index a2f156f6c3..663f441f2f 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -57,6 +57,8 @@ namespace osu.Game.Scoring public List GetAllUsableScores() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList(); + public IEnumerable QueryScores(Expression> query) => ModelStore.ConsumableItems.AsNoTracking().Where(query); + public ScoreInfo Query(Expression> query) => ModelStore.ConsumableItems.AsNoTracking().FirstOrDefault(query); } } diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 2b94c11bf9..714010b42c 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -179,6 +179,9 @@ namespace osu.Game.Screens.Select.Leaderboards private APIAccess api; private BeatmapInfo beatmap; + [Resolved] + private ScoreManager scoreManager { get; set; } + private ScheduledDelegate pendingUpdateScores; public BeatmapInfo Beatmap @@ -216,6 +219,8 @@ namespace osu.Game.Screens.Select.Leaderboards api.OnStateChange -= handleApiStateChange; } + public void RefreshScores() => updateScores(); + private GetScoresRequest getScoresRequest; private void handleApiStateChange(APIState oldState, APIState newState) @@ -242,8 +247,8 @@ namespace osu.Game.Screens.Select.Leaderboards { if (Scope == LeaderboardScope.Local) { - // TODO: get local scores from wherever here. - PlaceholderState = PlaceholderState.NoScores; + Scores = scoreManager.QueryScores(s => s.BeatmapInfo.ID == Beatmap.ID).ToArray(); + PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; return; } diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 1a405190e7..b5d333aee4 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -108,6 +108,8 @@ namespace osu.Game.Screens.Select removeAutoModOnResume = false; } + BeatmapDetails.Leaderboard.RefreshScores(); + Beatmap.Value.Track.Looping = true; base.OnResuming(last); From b1c5b43767073e76ab0514e381a6217dc974e8f1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Nov 2018 18:46:47 +0900 Subject: [PATCH 10/11] Fix post-rebase errors --- osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 714010b42c..a65cc6f096 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -247,7 +247,7 @@ namespace osu.Game.Screens.Select.Leaderboards { if (Scope == LeaderboardScope.Local) { - Scores = scoreManager.QueryScores(s => s.BeatmapInfo.ID == Beatmap.ID).ToArray(); + Scores = scoreManager.QueryScores(s => s.Beatmap.ID == Beatmap.ID).ToArray(); PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; return; } From f80a30cba453f8fd53c2fec13326e3e14f846334 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 30 Nov 2018 18:52:31 +0900 Subject: [PATCH 11/11] Fix null being serialized --- osu.Game/Scoring/ScoreInfo.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 07f1181a69..1ca62471f4 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -44,7 +44,8 @@ namespace osu.Game.Scoring { get { - if (mods != null) return mods; + if (mods != null) + return mods; if (modsJson == null) return Array.Empty(); @@ -65,7 +66,16 @@ namespace osu.Game.Scoring [Column("Mods")] public string ModsJson { - get => modsJson ?? (modsJson = JsonConvert.SerializeObject(mods)); + get + { + if (modsJson != null) + return modsJson; + + if (mods == null) + return null; + + return modsJson = JsonConvert.SerializeObject(mods); + } set { modsJson = value;