From 78a7564acd527ad54ee71cbaf003022b5b7c9630 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 24 Mar 2018 16:00:18 -0700 Subject: [PATCH 01/70] Score multiplier edits --- .../Mods/ManiaModDualStages.cs | 2 +- .../Mods/ManiaModRandom.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 2 +- osu.Game.Tests/Visual/TestCaseMods.cs | 11 ++++--- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 31 ++++++++++++++++--- osu.Game/Rulesets/Mods/ModAutoplay.cs | 2 +- osu.Game/Rulesets/Mods/ModRelax.cs | 2 +- 7 files changed, 37 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs index a1f9e0290e..949a2c950c 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override string Name => "Dual Stages"; public override string ShortenedName => "DS"; public override string Description => @"Double the stages, double the fun!"; - public override double ScoreMultiplier => 0; + public override double ScoreMultiplier => 1; public void ApplyToBeatmapConverter(BeatmapConverter beatmapConverter) { diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs index df0f9a5437..dd528cb163 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override string ShortenedName => "RD"; public override FontAwesome Icon => FontAwesome.fa_osu_dice; public override string Description => @"Shuffle around the keys!"; - public override double ScoreMultiplier => 0; + public override double ScoreMultiplier => 1; public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 0c842143e4..c78274e453 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string ShortenedName => "AP"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot; public override string Description => @"Automatic cursor movement - just follow the rhythm."; - public override double ScoreMultiplier => 0; + public override double ScoreMultiplier => 1; public override bool Ranked => false; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) }; } diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index 039d8bfdb6..4f841d3ee2 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual private void testManiaMods(ManiaRuleset ruleset) { - testMultiplierTextUnranked(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom)); + testRankedTextUnranked(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom)); } private void testSingleMod(Mod mod) @@ -182,13 +182,13 @@ namespace osu.Game.Tests.Visual checkLabelColor(Color4.White); } - private void testMultiplierTextUnranked(Mod mod) + private void testRankedTextUnranked(Mod mod) { - AddAssert("check for ranked", () => !modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix)); + AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.EndsWith(unranked_suffix)); selectNext(mod); - AddAssert("check for unranked", () => modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix)); + AddAssert("check for unranked", () => modSelect.RankedLabel.Text.EndsWith(unranked_suffix)); selectPrevious(mod); - AddAssert("check for ranked", () => !modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix)); + AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.EndsWith(unranked_suffix)); } private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1)); @@ -224,6 +224,7 @@ namespace osu.Game.Tests.Visual } public new OsuSpriteText MultiplierLabel => base.MultiplierLabel; + public new OsuSpriteText RankedLabel => base.RankedLabel; public new TriangleButton DeselectAllButton => base.DeselectAllButton; public new Color4 LowMultiplierColour => base.LowMultiplierColour; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index d8c95da94f..21c1082191 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -27,10 +27,11 @@ namespace osu.Game.Overlays.Mods { private const float content_width = 0.8f; - protected Color4 LowMultiplierColour, HighMultiplierColour; + protected Color4 LowMultiplierColour, HighMultiplierColour, RankedColour; protected readonly TriangleButton DeselectAllButton; protected readonly OsuSpriteText MultiplierLabel; + protected readonly OsuSpriteText RankedLabel; private readonly FillFlowContainer footerContainer; protected override bool BlockPassThroughKeyboard => false; @@ -55,8 +56,9 @@ namespace osu.Game.Overlays.Mods { SelectedMods.ValueChanged += selectedModsChanged; - LowMultiplierColour = colours.Red; + LowMultiplierColour = colours.Yellow; HighMultiplierColour = colours.Green; + RankedColour = colours.Red; if (osu != null) Ruleset.BindTo(osu.Ruleset); @@ -98,15 +100,24 @@ namespace osu.Game.Overlays.Mods } MultiplierLabel.Text = $"{multiplier:N2}x"; - if (!ranked) - MultiplierLabel.Text += " (Unranked)"; - if (multiplier > 1.0) MultiplierLabel.FadeColour(HighMultiplierColour, 200); else if (multiplier < 1.0) MultiplierLabel.FadeColour(LowMultiplierColour, 200); else MultiplierLabel.FadeColour(Color4.White, 200); + + RankedLabel.Text = null; + if (!ranked) + { + RankedLabel.Text += " (Unranked)"; + RankedLabel.FadeColour(RankedColour, 200); + } + else + { + RankedLabel.Text = null; + RankedLabel.FadeColour(Color4.White, 200); + } } protected override void PopOut() @@ -362,6 +373,16 @@ namespace osu.Game.Overlays.Mods } }, MultiplierLabel = new OsuSpriteText + { + Font = @"Exo2.0-Bold", + TextSize = 30, + Shadow = true, + Margin = new MarginPadding + { + Top = 5 + } + }, + RankedLabel = new OsuSpriteText { Font = @"Exo2.0-Bold", TextSize = 30, diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs index 9f45cada7e..8ab12cd30f 100644 --- a/osu.Game/Rulesets/Mods/ModAutoplay.cs +++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mods public override string ShortenedName => "AT"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto; public override string Description => "Watch a perfect automated play through the song."; - public override double ScoreMultiplier => 0; + public override double ScoreMultiplier => 1; public bool AllowFail => false; public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) }; } diff --git a/osu.Game/Rulesets/Mods/ModRelax.cs b/osu.Game/Rulesets/Mods/ModRelax.cs index e8328c3ac7..071f5d5a66 100644 --- a/osu.Game/Rulesets/Mods/ModRelax.cs +++ b/osu.Game/Rulesets/Mods/ModRelax.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Relax"; public override string ShortenedName => "RX"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_relax; - public override double ScoreMultiplier => 0; + public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModSuddenDeath) }; } } From 90d763fda51b8a5255179ee41ec466ebb9e1cc4b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 25 Mar 2018 10:00:30 -0700 Subject: [PATCH 02/70] Apply review changes and suggestions --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 1 - osu.Game.Tests/Visual/TestCaseMods.cs | 12 ++++----- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 27 ++++++++++++------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index c78274e453..b5e9540eae 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot; public override string Description => @"Automatic cursor movement - just follow the rhythm."; public override double ScoreMultiplier => 1; - public override bool Ranked => false; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) }; } } diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index 4f841d3ee2..b194462a96 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual [Description("mod select and icon display")] public class TestCaseMods : OsuTestCase { - private const string unranked_suffix = " (Unranked)"; + private const string unranked_suffix = "(Unranked)"; private RulesetStore rulesets; private ModDisplay modDisplay; @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual private void testManiaMods(ManiaRuleset ruleset) { - testRankedTextUnranked(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom)); + testRankedText(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom)); } private void testSingleMod(Mod mod) @@ -182,13 +182,13 @@ namespace osu.Game.Tests.Visual checkLabelColor(Color4.White); } - private void testRankedTextUnranked(Mod mod) + private void testRankedText(Mod mod) { - AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.EndsWith(unranked_suffix)); + AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.Equals(unranked_suffix)); selectNext(mod); - AddAssert("check for unranked", () => modSelect.RankedLabel.Text.EndsWith(unranked_suffix)); + AddAssert("check for unranked", () => modSelect.RankedLabel.Text.Equals(unranked_suffix)); selectPrevious(mod); - AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.EndsWith(unranked_suffix)); + AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.Equals(unranked_suffix)); } private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1)); diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 21c1082191..604e683917 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -30,6 +30,7 @@ namespace osu.Game.Overlays.Mods protected Color4 LowMultiplierColour, HighMultiplierColour, RankedColour; protected readonly TriangleButton DeselectAllButton; + protected readonly OsuSpriteText ScoreLabel; protected readonly OsuSpriteText MultiplierLabel; protected readonly OsuSpriteText RankedLabel; private readonly FillFlowContainer footerContainer; @@ -56,9 +57,9 @@ namespace osu.Game.Overlays.Mods { SelectedMods.ValueChanged += selectedModsChanged; - LowMultiplierColour = colours.Yellow; + LowMultiplierColour = colours.Red; HighMultiplierColour = colours.Green; - RankedColour = colours.Red; + RankedColour = colours.Blue; if (osu != null) Ruleset.BindTo(osu.Ruleset); @@ -99,6 +100,14 @@ namespace osu.Game.Overlays.Mods ranked &= mod.Ranked; } + ScoreLabel.Text = "Score Multiplier:"; + if (multiplier > 1.0) + ScoreLabel.FadeColour(HighMultiplierColour, 200); + else if (multiplier < 1.0) + ScoreLabel.FadeColour(LowMultiplierColour, 200); + else + ScoreLabel.FadeColour(Color4.White, 200); + MultiplierLabel.Text = $"{multiplier:N2}x"; if (multiplier > 1.0) MultiplierLabel.FadeColour(HighMultiplierColour, 200); @@ -110,14 +119,11 @@ namespace osu.Game.Overlays.Mods RankedLabel.Text = null; if (!ranked) { - RankedLabel.Text += " (Unranked)"; + RankedLabel.Text = "(Unranked)"; RankedLabel.FadeColour(RankedColour, 200); } else - { - RankedLabel.Text = null; RankedLabel.FadeColour(Color4.White, 200); - } } protected override void PopOut() @@ -362,14 +368,14 @@ namespace osu.Game.Overlays.Mods Right = 20 } }, - new OsuSpriteText + ScoreLabel = new OsuSpriteText { - Text = @"Score Multiplier: ", TextSize = 30, Shadow = true, Margin = new MarginPadding { - Top = 5 + Top = 5, + Right = 10 } }, MultiplierLabel = new OsuSpriteText @@ -389,7 +395,8 @@ namespace osu.Game.Overlays.Mods Shadow = true, Margin = new MarginPadding { - Top = 5 + Top = 5, + Left = 10 } } } From ac9527147f1f81cd9fd65911cca8eb833516a78a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 27 Mar 2018 03:05:05 -0700 Subject: [PATCH 03/70] Fix transitioning of unranked label --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 604e683917..37a789190a 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -116,14 +116,13 @@ namespace osu.Game.Overlays.Mods else MultiplierLabel.FadeColour(Color4.White, 200); - RankedLabel.Text = null; + RankedLabel.Text = "(Unranked)"; + RankedLabel.FadeColour(RankedColour, 200); + RankedLabel.FadeOut(200); if (!ranked) { - RankedLabel.Text = "(Unranked)"; - RankedLabel.FadeColour(RankedColour, 200); + RankedLabel.FadeIn(200); } - else - RankedLabel.FadeColour(Color4.White, 200); } protected override void PopOut() From 5457f17e792af7bbcebfc758a40fa73eba427270 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 28 Mar 2018 19:53:15 -0700 Subject: [PATCH 04/70] Clean up code from reviews --- osu.Game.Tests/Visual/TestCaseMods.cs | 9 ++++--- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 29 +++++++--------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index b194462a96..73bfe9b7bb 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -184,11 +184,14 @@ namespace osu.Game.Tests.Visual private void testRankedText(Mod mod) { - AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.Equals(unranked_suffix)); + AddWaitStep(1, "wait for fade"); + AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha.Equals(0)); selectNext(mod); - AddAssert("check for unranked", () => modSelect.RankedLabel.Text.Equals(unranked_suffix)); + AddWaitStep(1, "wait for fade"); + AddAssert("check for unranked", () => !modSelect.RankedLabel.Alpha.Equals(0)); selectPrevious(mod); - AddAssert("check for ranked", () => !modSelect.RankedLabel.Text.Equals(unranked_suffix)); + AddWaitStep(1, "wait for fade"); + AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha.Equals(0)); } private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1)); diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 37a789190a..f307d4c92f 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -27,12 +27,10 @@ namespace osu.Game.Overlays.Mods { private const float content_width = 0.8f; - protected Color4 LowMultiplierColour, HighMultiplierColour, RankedColour; + protected Color4 LowMultiplierColour, HighMultiplierColour; protected readonly TriangleButton DeselectAllButton; - protected readonly OsuSpriteText ScoreLabel; - protected readonly OsuSpriteText MultiplierLabel; - protected readonly OsuSpriteText RankedLabel; + protected readonly OsuSpriteText MultiplierLabel, RankedLabel; private readonly FillFlowContainer footerContainer; protected override bool BlockPassThroughKeyboard => false; @@ -59,7 +57,6 @@ namespace osu.Game.Overlays.Mods LowMultiplierColour = colours.Red; HighMultiplierColour = colours.Green; - RankedColour = colours.Blue; if (osu != null) Ruleset.BindTo(osu.Ruleset); @@ -100,14 +97,6 @@ namespace osu.Game.Overlays.Mods ranked &= mod.Ranked; } - ScoreLabel.Text = "Score Multiplier:"; - if (multiplier > 1.0) - ScoreLabel.FadeColour(HighMultiplierColour, 200); - else if (multiplier < 1.0) - ScoreLabel.FadeColour(LowMultiplierColour, 200); - else - ScoreLabel.FadeColour(Color4.White, 200); - MultiplierLabel.Text = $"{multiplier:N2}x"; if (multiplier > 1.0) MultiplierLabel.FadeColour(HighMultiplierColour, 200); @@ -116,13 +105,10 @@ namespace osu.Game.Overlays.Mods else MultiplierLabel.FadeColour(Color4.White, 200); - RankedLabel.Text = "(Unranked)"; - RankedLabel.FadeColour(RankedColour, 200); - RankedLabel.FadeOut(200); - if (!ranked) - { + if (ranked) + RankedLabel.FadeOut(200); + else RankedLabel.FadeIn(200); - } } protected override void PopOut() @@ -367,8 +353,9 @@ namespace osu.Game.Overlays.Mods Right = 20 } }, - ScoreLabel = new OsuSpriteText + new OsuSpriteText { + Text = @"Score Multiplier:", TextSize = 30, Shadow = true, Margin = new MarginPadding @@ -390,7 +377,9 @@ namespace osu.Game.Overlays.Mods RankedLabel = new OsuSpriteText { Font = @"Exo2.0-Bold", + Text = @"(Unranked)", TextSize = 30, + Colour = OsuColour.FromHex(@"66ccff"), Shadow = true, Margin = new MarginPadding { From 1bebda61f8d6bd048f26d60ae5cbd6b2d508eafd Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 31 Mar 2018 10:51:44 -0700 Subject: [PATCH 05/70] Use "==" instead of "equals" --- osu.Game.Tests/Visual/TestCaseMods.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index 73bfe9b7bb..201804fa74 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -185,13 +185,13 @@ namespace osu.Game.Tests.Visual private void testRankedText(Mod mod) { AddWaitStep(1, "wait for fade"); - AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha.Equals(0)); + AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha == 0); selectNext(mod); AddWaitStep(1, "wait for fade"); - AddAssert("check for unranked", () => !modSelect.RankedLabel.Alpha.Equals(0)); + AddAssert("check for unranked", () => !(modSelect.RankedLabel.Alpha == 0)); selectPrevious(mod); AddWaitStep(1, "wait for fade"); - AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha.Equals(0)); + AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha == 0); } private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1)); From ee7db92e6bb5aba9a792b6b84ee3a22ac9e8682c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 3 Apr 2018 21:01:02 -0700 Subject: [PATCH 06/70] Simplify negative equality expression --- osu.Game.Tests/Visual/TestCaseMods.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index 201804fa74..8ee3c6e911 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Visual AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha == 0); selectNext(mod); AddWaitStep(1, "wait for fade"); - AddAssert("check for unranked", () => !(modSelect.RankedLabel.Alpha == 0)); + AddAssert("check for unranked", () => modSelect.RankedLabel.Alpha != 0); selectPrevious(mod); AddWaitStep(1, "wait for fade"); AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha == 0); From 5e4f83b80b158cdf0ddadd60db430a0fc1d83a15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 May 2018 17:29:52 +0900 Subject: [PATCH 07/70] Add more correct catch playfield sizing --- osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 070dc19a6f..52763e09af 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -32,6 +32,8 @@ namespace osu.Game.Rulesets.Catch.UI public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo); + protected override Vector2 PlayfieldArea => new Vector2(0.86f); // matches stable's vertical offset for catcher plate + protected override DrawableHitObject GetVisualRepresentation(CatchHitObject h) { switch (h) From 3fe25fe67d67d17eb5f0f6bca374317e97a17c96 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 May 2018 17:32:07 +0900 Subject: [PATCH 08/70] Fix catcher sizing to (roughly) match stable --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 34 ++++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 181536a91e..59d5ecd07f 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatcherArea : Container { - public const float CATCHER_SIZE = 172; + public const float CATCHER_SIZE = 84; protected readonly Catcher MovableCatcher; @@ -99,8 +99,6 @@ namespace osu.Game.Rulesets.Catch.UI public class Catcher : Container, IKeyBindingHandler { - private Texture texture; - private Container caughtFruit; public Container ExplodingFruitTarget; @@ -121,10 +119,8 @@ namespace osu.Game.Rulesets.Catch.UI } [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load() { - texture = textures.Get(@"Play/Catch/fruit-catcher-idle"); - Children = new Drawable[] { caughtFruit = new Container @@ -196,13 +192,7 @@ namespace osu.Game.Rulesets.Catch.UI Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); } - private Sprite createCatcherSprite() => new Sprite - { - Size = new Vector2(CATCHER_SIZE), - FillMode = FillMode.Fill, - Texture = texture, - OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly. - }; + private Sprite createCatcherSprite() => new CatcherSprite(); /// /// Add a caught fruit to the catcher's stack. @@ -411,6 +401,24 @@ namespace osu.Game.Rulesets.Catch.UI f.Expire(); } } + + private class CatcherSprite : Sprite + { + public CatcherSprite() + { + Size = new Vector2(CATCHER_SIZE); + FillMode = FillMode.Fill; + + // Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling. + OriginPosition = new Vector2(-0.02f, 0.06f) * CATCHER_SIZE; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + Texture = textures.Get(@"Play/Catch/fruit-catcher-idle"); + } + } } } } From bf25e81c945398bbada55b44ebf29413c25363c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 May 2018 17:32:22 +0900 Subject: [PATCH 09/70] Make drawable bananas testable --- .../TestCaseCatcherArea.cs | 2 +- .../TestCaseFruitObjects.cs | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs index f239290ed4..5119260c53 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatcherArea.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) { Anchor = Anchor.CentreLeft, - Origin = Anchor.BottomLeft + Origin = Anchor.TopLeft }, }; } diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs index 275752523d..e77dd76353 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseFruitObjects.cs @@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Catch.Tests typeof(DrawableCatchHitObject), typeof(DrawableFruit), typeof(DrawableDroplet), + typeof(BananaShower), typeof(Pulp), }; @@ -53,12 +54,19 @@ namespace osu.Game.Rulesets.Catch.Tests private DrawableFruit createDrawable(int index) { - var fruit = new Fruit - { - StartTime = 1000000000000, - IndexInBeatmap = index, - Scale = 1.5f, - }; + Fruit fruit = index == 5 + ? new BananaShower.Banana + { + StartTime = 1000000000000, + IndexInBeatmap = index, + Scale = 1.5f, + } + : new Fruit + { + StartTime = 1000000000000, + IndexInBeatmap = index, + Scale = 1.5f, + }; return new DrawableFruit(fruit) { From f5ab93a712933f6540c852aa8cda691470221e98 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 May 2018 17:33:05 +0900 Subject: [PATCH 10/70] Make all drawable fruit absolute values easily scalable --- .../Objects/Drawable/DrawableFruit.cs | 41 +++++++++---------- .../Objects/Drawable/Pieces/Pulp.cs | 24 +++++++---- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs index 41792b10a4..4603148114 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs @@ -18,12 +18,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { private Circle border; + private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust; + + /// + /// Because we're adding a border around the fruit, we need to scale down some. + /// + private const float radius_adjust = 1.1f; + public DrawableFruit(Fruit h) : base(h) { Origin = Anchor.Centre; - Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS); + Size = new Vector2(drawable_radius); Masking = false; Rotation = (float)(RNG.NextDouble() - 0.5f) * 40; @@ -44,14 +51,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { Hollow = !HitObject.HyperDash, Type = EdgeEffectType.Glow, - Radius = 4, + Radius = 4 * radius_adjust, Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f) }, - Size = new Vector2(Height * 1.5f), + Size = new Vector2(Height), Anchor = Anchor.Centre, Origin = Anchor.Centre, BorderColour = Color4.White, - BorderThickness = 4f, + BorderThickness = 3f * radius_adjust, Children = new Framework.Graphics.Drawable[] { new Box @@ -82,8 +89,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation) { - const float large_pulp_3 = 13f; - const float distance_from_centre_3 = 0.23f; + const float large_pulp_3 = 8f * radius_adjust; + const float distance_from_centre_3 = 0.15f; const float large_pulp_4 = large_pulp_3 * 0.925f; const float distance_from_centre_4 = distance_from_centre_3 / 0.925f; @@ -106,11 +113,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { new Pulp { - Anchor = Anchor.TopCentre, - Origin = Anchor.BottomCentre, AccentColour = AccentColour, Size = new Vector2(small_pulp), - Y = 0.05f, + Y = -0.34f, }, new Pulp { @@ -146,11 +151,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { new Pulp { - Anchor = Anchor.TopCentre, - Origin = Anchor.BottomCentre, AccentColour = AccentColour, Size = new Vector2(small_pulp), - Y = 0.1f, + Y = -0.3f, }, new Pulp { @@ -186,11 +189,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { new Pulp { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, AccentColour = AccentColour, Size = new Vector2(small_pulp), - Y = -0.1f, + Y = -0.33f, }, new Pulp { @@ -220,10 +221,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { new Pulp { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, AccentColour = AccentColour, Size = new Vector2(small_pulp), + Y = -0.25f, }, new Pulp { @@ -253,16 +253,15 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { new Pulp { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, AccentColour = AccentColour, Size = new Vector2(small_pulp), - Y = -0.15f + Y = -0.3f }, new Pulp { AccentColour = AccentColour, - Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3), + Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f), + Y = 0.05f, }, } }; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs index d17a72a165..250dc8c7f1 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs @@ -29,14 +29,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces set { accentColour = value; - - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Radius = 8, - Colour = accentColour.Darken(0.2f).Opacity(0.75f) - }; + if (IsLoaded) updateAccentColour(); } } + + private void updateAccentColour() + { + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = Size.X / 2, + Colour = accentColour.Darken(0.2f).Opacity(0.75f) + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateAccentColour(); + } } } From 31cbec99a1ea272a82951187355d536ab4a03e33 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 28 May 2018 18:12:49 +0900 Subject: [PATCH 11/70] Fix mania hold notes displaying judgements --- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs | 2 ++ osu.Game.Rulesets.Mania/UI/Column.cs | 2 +- osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 8791e8ed86..f7de503fb3 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// public class DrawableHoldNote : DrawableManiaHitObject, IKeyBindingHandler { + public override bool DisplayJudgement => false; + private readonly DrawableNote head; private readonly DrawableNote tail; diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 52d514221d..28cd1b6b39 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -213,7 +213,7 @@ namespace osu.Game.Rulesets.Mania.UI internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) { - if (!judgement.IsHit) + if (!judgement.IsHit || !judgedObject.DisplayJudgement) return; explosionContainer.Add(new HitExplosion(judgedObject)); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 904be3a9e3..605794c795 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -171,6 +171,9 @@ namespace osu.Game.Rulesets.Mania.UI internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) { + if (!judgedObject.DisplayJudgement) + return; + judgements.Clear(); judgements.Add(new DrawableManiaJudgement(judgement, judgedObject) { From 5be46307fdeda27cdc5556d0ca1303cff98285dc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 28 May 2018 19:43:59 +0900 Subject: [PATCH 12/70] Fix results screen parallax being cut off Alternative to / closes #2549. Didn't want to reference the toolbar as was done, also wanted to remove the awkward scaling factors so rather than scaling down the inner one, we scale up the outer one. --- osu.Game/Screens/Ranking/Results.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 32161a0b8e..7cbd2e4403 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -57,6 +57,7 @@ namespace osu.Game.Screens.Ranking { base.OnEntering(last); (Background as BackgroundScreenBeatmap)?.BlurTo(background_blur, 2500, Easing.OutQuint); + Background.ScaleTo(1.1f, transition_time, Easing.OutQuint); allCircles.ForEach(c => { @@ -102,6 +103,8 @@ namespace osu.Game.Screens.Ranking c.ScaleTo(0, transition_time, Easing.OutSine); }); + Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint); + Content.FadeOut(transition_time / 4); return base.OnExiting(next); @@ -160,7 +163,6 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - Scale = new Vector2(1 / circle_outer_scale / overscan), Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] From e920b8d5774beb09455e462ac09347e768e81a7e Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 19:11:26 -0300 Subject: [PATCH 13/70] Add UpdateableBeatmapSetCover. --- .../Drawables/UpdateableBeatmapSetCover.cs | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs new file mode 100644 index 0000000000..e25f5a9431 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs @@ -0,0 +1,78 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; + +namespace osu.Game.Beatmaps.Drawables +{ + public class UpdateableBeatmapSetCover : Container + { + private Drawable displayedCover; + + private BeatmapSetInfo beatmapSet; + public BeatmapSetInfo BeatmapSet + { + get { return beatmapSet; } + set + { + if (value == beatmapSet) return; + beatmapSet = value; + + if (IsLoaded) + updateCover(); + } + } + + private BeatmapSetCoverType coverType = BeatmapSetCoverType.Cover; + public BeatmapSetCoverType CoverType + { + get { return coverType; } + set + { + if (value == coverType) return; + coverType = value; + + if (IsLoaded) + updateCover(); + } + } + + public UpdateableBeatmapSetCover() + { + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateCover(); + } + + private void updateCover() + { + displayedCover?.FadeOut(400); + displayedCover?.Expire(); + + if (beatmapSet != null) + { + Add(displayedCover = new DelayedLoadWrapper( + new BeatmapSetCover(beatmapSet, coverType) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), + }) + ); + } + } + } +} From bdfb5752cd46eda4f5f0e908e3aa721eb5222e54 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 19:31:20 -0300 Subject: [PATCH 14/70] Update existing drawables to use UpdateableBeatmapSetCover. --- osu.Game/Overlays/BeatmapSet/Header.cs | 25 +++------------ osu.Game/Overlays/Direct/DirectPanel.cs | 23 ++----------- .../Historical/DrawableMostPlayedRow.cs | 14 +++----- .../Screens/Multi/Components/DrawableRoom.cs | 29 +++-------------- .../Screens/Multi/Components/RoomInspector.cs | 32 +++---------------- 5 files changed, 19 insertions(+), 104 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 8833a89479..033f0b22d0 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet private const float buttons_spacing = 5; private readonly Box tabsBg; - private readonly Container coverContainer; + private readonly UpdateableBeatmapSetCover cover; private readonly OsuSpriteText title, artist; private readonly Container noVideoButtons; private readonly FillFlowContainer videoButtons; @@ -36,7 +36,6 @@ namespace osu.Game.Overlays.BeatmapSet public Details Details; private BeatmapManager beatmaps; - private DelayedLoadWrapper cover; public readonly BeatmapPicker Picker; @@ -63,7 +62,7 @@ namespace osu.Game.Overlays.BeatmapSet artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty; onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None; - cover?.FadeOut(400, Easing.Out); + cover.BeatmapSet = null; if (BeatmapSet != null) { downloadButtonsContainer.FadeIn(transition_duration); @@ -72,18 +71,7 @@ namespace osu.Game.Overlays.BeatmapSet noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration); videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); - coverContainer.Add(cover = new DelayedLoadWrapper( - new BeatmapSetCover(BeatmapSet) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }, 300) - { - RelativeSizeAxes = Axes.Both, - }); + cover.BeatmapSet = BeatmapSet; } else { @@ -130,12 +118,7 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - coverContainer = new Container + cover = new UpdateableBeatmapSetCover { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index cc0123dabc..df784252ce 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -27,8 +27,6 @@ namespace osu.Game.Overlays.Direct { public readonly BeatmapSetInfo SetInfo; - protected Box BlackBackground; - private const double hover_transition_time = 400; private Container content; @@ -81,12 +79,6 @@ namespace osu.Game.Overlays.Direct EdgeEffect = edgeEffectNormal, Children = new[] { - // temporary blackness until the actual background loads. - BlackBackground = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, CreateBackground(), progressBar = new ProgressBar { @@ -215,21 +207,10 @@ namespace osu.Game.Overlays.Direct return icons; } - protected Drawable CreateBackground() => new DelayedLoadWrapper( - new BeatmapSetCover(SetInfo) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - OnLoadComplete = d => - { - d.FadeInFromZero(400, Easing.Out); - BlackBackground.Delay(400).FadeOut(); - }, - }, 300) + protected Drawable CreateBackground() => new UpdateableBeatmapSetCover { RelativeSizeAxes = Axes.Both, + BeatmapSet = SetInfo, }; public class Statistic : FillFlowContainer diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedRow.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedRow.cs index be8e09105b..0a2b2fe121 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedRow.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedRow.cs @@ -24,19 +24,13 @@ namespace osu.Game.Overlays.Profile.Sections.Historical this.playCount = playCount; } - protected override Drawable CreateLeftVisual() => new DelayedLoadWrapper(new BeatmapSetCover(beatmap.BeatmapSet, BeatmapSetCoverType.List) + protected override Drawable CreateLeftVisual() => new UpdateableBeatmapSetCover { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fit, - RelativeSizeAxes = Axes.Both, - OnLoadComplete = d => d.FadeInFromZero(500, Easing.OutQuint) - }) - { - Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - RelativeSizeAxes = Axes.None, + Origin = Anchor.CentreLeft, Size = new Vector2(80, 50), + BeatmapSet = beatmap.BeatmapSet, + CoverType = BeatmapSetCoverType.List, }; [BackgroundDependencyLoader(true)] diff --git a/osu.Game/Screens/Multi/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs index 1851f4618e..83d86d8159 100644 --- a/osu.Game/Screens/Multi/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Multi.Components private void load(OsuColour colours, LocalisationEngine localisation) { Box sideStrip; - Container coverContainer; + UpdateableBeatmapSetCover cover; OsuSpriteText name, status, beatmapTitle, beatmapDash, beatmapArtist; ParticipantInfo participantInfo; ModeTypeInfo modeTypeInfo; @@ -146,24 +146,12 @@ namespace osu.Game.Screens.Multi.Components RelativeSizeAxes = Axes.Y, Width = side_strip_width, }, - new Container + cover = new UpdateableBeatmapSetCover { Width = cover_width, RelativeSizeAxes = Axes.Y, Masking = true, Margin = new MarginPadding { Left = side_strip_width }, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - coverContainer = new Container - { - RelativeSizeAxes = Axes.Both, - }, - }, }, new Container { @@ -263,23 +251,14 @@ namespace osu.Game.Screens.Multi.Components if (b != null) { - coverContainer.FadeIn(transition_duration); - - LoadComponentAsync(new BeatmapSetCover(b.BeatmapSet) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }, coverContainer.Add); - + cover.BeatmapSet = b.BeatmapSet; beatmapTitle.Current = localisation.GetUnicodePreference(b.Metadata.TitleUnicode, b.Metadata.Title); beatmapDash.Text = @" - "; beatmapArtist.Current = localisation.GetUnicodePreference(b.Metadata.ArtistUnicode, b.Metadata.Artist); } else { - coverContainer.FadeOut(transition_duration); + cover.BeatmapSet = null; beatmapTitle.Current = null; beatmapArtist.Current = null; diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index 3bd054b042..a282e56d22 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Multi.Components private OsuColour colours; private Box statusStrip; - private Container coverContainer; + private UpdateableBeatmapSetCover cover; private FillFlowContainer topFlow, participantsFlow, participantNumbersFlow, infoPanelFlow; private OsuSpriteText name, status; private ScrollContainer participantsScroll; @@ -105,21 +105,9 @@ namespace osu.Game.Screens.Multi.Components Masking = true, Children = new Drawable[] { - new Container + cover = new UpdateableBeatmapSetCover { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - coverContainer = new Container - { - RelativeSizeAxes = Axes.Both, - }, - }, }, new Box { @@ -294,17 +282,7 @@ namespace osu.Game.Screens.Multi.Components if (b != null) { - coverContainer.FadeIn(transition_duration); - - LoadComponentAsync(new BeatmapSetCover(b.BeatmapSet) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }, coverContainer.Add); - + cover.BeatmapSet = b.BeatmapSet; beatmapTitle.Current = localisation.GetUnicodePreference(b.Metadata.TitleUnicode, b.Metadata.Title); beatmapDash.Text = @" - "; beatmapArtist.Current = localisation.GetUnicodePreference(b.Metadata.ArtistUnicode, b.Metadata.Artist); @@ -312,7 +290,7 @@ namespace osu.Game.Screens.Multi.Components } else { - coverContainer.FadeOut(transition_duration); + cover.BeatmapSet = null; beatmapTitle.Current = null; beatmapArtist.Current = null; @@ -367,7 +345,7 @@ namespace osu.Game.Screens.Multi.Components { if (Room == null) { - coverContainer.FadeOut(transition_duration); + cover.BeatmapSet = null; participantsFlow.FadeOut(transition_duration); participantNumbersFlow.FadeOut(transition_duration); infoPanelFlow.FadeOut(transition_duration); From 8b36e1dad088095b0e9aa4b8e7cc74f8fae1390d Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 23:13:56 -0300 Subject: [PATCH 15/70] Add BeatmapTitle to encapsulate multiplayer beatmap title display logic. (cherry picked from commit 58e65afb45fbc675186e470cc4a268d9eaa2a539) --- .../Screens/Multi/Components/BeatmapTitle.cs | 90 +++++++++++++++++++ .../Screens/Multi/Components/DrawableRoom.cs | 40 ++------- .../Screens/Multi/Components/RoomInspector.cs | 37 ++------ 3 files changed, 104 insertions(+), 63 deletions(-) create mode 100644 osu.Game/Screens/Multi/Components/BeatmapTitle.cs diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs new file mode 100644 index 0000000000..a6cc472335 --- /dev/null +++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs @@ -0,0 +1,90 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Multi.Components +{ + public class BeatmapTitle : FillFlowContainer + { + private readonly OsuSpriteText beatmapTitle, beatmapDash, beatmapArtist; + + private LocalisationEngine localisation; + + public float TextSize + { + set { beatmapTitle.TextSize = beatmapDash.TextSize = beatmapArtist.TextSize = value; } + } + + private BeatmapInfo beatmap; + public BeatmapInfo Beatmap + { + get { return beatmap; } + set + { + if (value == beatmap) return; + beatmap = value; + + if (IsLoaded) + updateText(); + } + } + + public BeatmapTitle() + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + + Children = new[] + { + beatmapTitle = new OsuSpriteText + { + Font = @"Exo2.0-BoldItalic", + }, + beatmapDash = new OsuSpriteText + { + Font = @"Exo2.0-BoldItalic", + }, + beatmapArtist = new OsuSpriteText + { + Font = @"Exo2.0-RegularItalic", + }, + }; + } + + [BackgroundDependencyLoader] + private void load(LocalisationEngine localisation) + { + this.localisation = localisation; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateText(); + } + + private void updateText() + { + if (beatmap == null) + { + beatmapTitle.Current = beatmapArtist.Current = null; + + beatmapTitle.Text = "Changing map"; + beatmapDash.Text = beatmapArtist.Text = string.Empty; + } + else + { + beatmapTitle.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title); + beatmapDash.Text = @" - "; + beatmapArtist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist); + } + } + } +} diff --git a/osu.Game/Screens/Multi/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs index 83d86d8159..f48846f707 100644 --- a/osu.Game/Screens/Multi/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -112,8 +112,9 @@ namespace osu.Game.Screens.Multi.Components { Box sideStrip; UpdateableBeatmapSetCover cover; - OsuSpriteText name, status, beatmapTitle, beatmapDash, beatmapArtist; + OsuSpriteText name, status; ParticipantInfo participantInfo; + BeatmapTitle beatmapTitle; ModeTypeInfo modeTypeInfo; Children = new Drawable[] @@ -193,30 +194,10 @@ namespace osu.Game.Screens.Multi.Components TextSize = 14, Font = @"Exo2.0-Bold", }, - new FillFlowContainer + beatmapTitle = new BeatmapTitle { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Colour = colours.Gray9, - Direction = FillDirection.Horizontal, - Children = new[] - { - beatmapTitle = new OsuSpriteText - { - TextSize = 14, - Font = @"Exo2.0-BoldItalic", - }, - beatmapDash = new OsuSpriteText - { - TextSize = 14, - Font = @"Exo2.0-BoldItalic", - }, - beatmapArtist = new OsuSpriteText - { - TextSize = 14, - Font = @"Exo2.0-RegularItalic", - }, - }, + TextSize = 14, + Colour = colours.Gray9 }, }, }, @@ -252,19 +233,12 @@ namespace osu.Game.Screens.Multi.Components if (b != null) { cover.BeatmapSet = b.BeatmapSet; - beatmapTitle.Current = localisation.GetUnicodePreference(b.Metadata.TitleUnicode, b.Metadata.Title); - beatmapDash.Text = @" - "; - beatmapArtist.Current = localisation.GetUnicodePreference(b.Metadata.ArtistUnicode, b.Metadata.Artist); + beatmapTitle.Beatmap = b; } else { cover.BeatmapSet = null; - - beatmapTitle.Current = null; - beatmapArtist.Current = null; - - beatmapTitle.Text = "Changing map"; - beatmapDash.Text = beatmapArtist.Text = string.Empty; + beatmapTitle.Beatmap = null; } }; diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index a282e56d22..ee3dea7c0d 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -82,7 +82,8 @@ namespace osu.Game.Screens.Multi.Components this.colours = colours; ModeTypeInfo modeTypeInfo; - OsuSpriteText participants, participantsSlash, maxParticipants, beatmapTitle, beatmapDash, beatmapArtist, beatmapAuthor; + OsuSpriteText participants, participantsSlash, maxParticipants, beatmapAuthor; + BeatmapTitle beatmapTitle; Children = new Drawable[] { @@ -203,28 +204,9 @@ namespace osu.Game.Screens.Multi.Components AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Margin = new MarginPadding { Left = 5 }, - Children = new[] + Children = new Drawable[] { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new[] - { - beatmapTitle = new OsuSpriteText - { - Font = @"Exo2.0-BoldItalic", - }, - beatmapDash = new OsuSpriteText - { - Font = @"Exo2.0-BoldItalic", - }, - beatmapArtist = new OsuSpriteText - { - Font = @"Exo2.0-RegularItalic", - }, - }, - }, + beatmapTitle = new BeatmapTitle(), beatmapAuthor = new OsuSpriteText { Anchor = Anchor.BottomLeft, @@ -283,20 +265,15 @@ namespace osu.Game.Screens.Multi.Components if (b != null) { cover.BeatmapSet = b.BeatmapSet; - beatmapTitle.Current = localisation.GetUnicodePreference(b.Metadata.TitleUnicode, b.Metadata.Title); - beatmapDash.Text = @" - "; - beatmapArtist.Current = localisation.GetUnicodePreference(b.Metadata.ArtistUnicode, b.Metadata.Artist); + beatmapTitle.Beatmap = b; beatmapAuthor.Text = $"mapped by {b.Metadata.Author}"; } else { cover.BeatmapSet = null; + beatmapTitle.Beatmap = null; - beatmapTitle.Current = null; - beatmapArtist.Current = null; - - beatmapTitle.Text = "Changing map"; - beatmapDash.Text = beatmapArtist.Text = beatmapAuthor.Text = string.Empty; + beatmapAuthor.Text = string.Empty; } }; From 8b8d10349e67f6f3987efaeb32e7c616fb578e71 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 23:33:13 -0300 Subject: [PATCH 16/70] Move RoomInspector info panel content to BeatmapModeInfo to share with Match. (cherry picked from commit 257d9d13ac81d85583314f8b5dfabf05661b1572) --- .../Multi/Components/BeatmapModeInfo.cs | 74 +++++++++++++++++++ .../Screens/Multi/Components/DrawableRoom.cs | 3 +- .../Screens/Multi/Components/ModeTypeInfo.cs | 3 +- .../Screens/Multi/Components/RoomInspector.cs | 60 +++------------ 4 files changed, 86 insertions(+), 54 deletions(-) create mode 100644 osu.Game/Screens/Multi/Components/BeatmapModeInfo.cs diff --git a/osu.Game/Screens/Multi/Components/BeatmapModeInfo.cs b/osu.Game/Screens/Multi/Components/BeatmapModeInfo.cs new file mode 100644 index 0000000000..8bd7d7ea06 --- /dev/null +++ b/osu.Game/Screens/Multi/Components/BeatmapModeInfo.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Multiplayer; +using OpenTK; + +namespace osu.Game.Screens.Multi.Components +{ + public class BeatmapModeInfo : FillFlowContainer + { + private readonly ModeTypeInfo modeTypeInfo; + private readonly BeatmapTitle beatmapTitle; + private readonly OsuSpriteText beatmapAuthor; + + public BeatmapInfo Beatmap + { + set + { + modeTypeInfo.Beatmap = beatmapTitle.Beatmap = value; + + if (value == null) + beatmapAuthor.Text = string.Empty; + else + beatmapAuthor.Text = $"mapped by {value.Metadata.Author}"; + } + } + + public GameType Type + { + set { modeTypeInfo.Type = value; } + } + + public BeatmapModeInfo() + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + LayoutDuration = 100; + Spacing = new Vector2(5f, 0f); + + Children = new Drawable[] + { + modeTypeInfo = new ModeTypeInfo(), + new Container + { + AutoSizeAxes = Axes.X, + Height = 30, + Margin = new MarginPadding { Left = 5 }, + Children = new Drawable[] + { + beatmapTitle = new BeatmapTitle(), + beatmapAuthor = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + TextSize = 14, + }, + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + beatmapAuthor.Colour = colours.Gray9; + } + } +} diff --git a/osu.Game/Screens/Multi/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs index f48846f707..70adf8c7db 100644 --- a/osu.Game/Screens/Multi/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; -using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; @@ -108,7 +107,7 @@ namespace osu.Game.Screens.Multi.Components } [BackgroundDependencyLoader] - private void load(OsuColour colours, LocalisationEngine localisation) + private void load(OsuColour colours) { Box sideStrip; UpdateableBeatmapSetCover cover; diff --git a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs index e3aba685a7..26c391586a 100644 --- a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs @@ -55,7 +55,8 @@ namespace osu.Game.Screens.Multi.Components public ModeTypeInfo() { - AutoSizeAxes = Axes.Both; + AutoSizeAxes = Axes.X; + Height = height; Children = new[] { diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index ee3dea7c0d..c3b7d3a7ad 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; @@ -39,8 +38,9 @@ namespace osu.Game.Screens.Multi.Components private OsuColour colours; private Box statusStrip; private UpdateableBeatmapSetCover cover; - private FillFlowContainer topFlow, participantsFlow, participantNumbersFlow, infoPanelFlow; + private FillFlowContainer topFlow, participantsFlow, participantNumbersFlow; private OsuSpriteText name, status; + private BeatmapModeInfo beatmapModeInfo; private ScrollContainer participantsScroll; private ParticipantInfo participantInfo; @@ -77,13 +77,12 @@ namespace osu.Game.Screens.Multi.Components } [BackgroundDependencyLoader] - private void load(OsuColour colours, LocalisationEngine localisation) + private void load(OsuColour colours) { this.colours = colours; ModeTypeInfo modeTypeInfo; OsuSpriteText participants, participantsSlash, maxParticipants, beatmapAuthor; - BeatmapTitle beatmapTitle; Children = new Drawable[] { @@ -189,35 +188,7 @@ namespace osu.Game.Screens.Multi.Components TextSize = 14, Font = @"Exo2.0-Bold", }, - infoPanelFlow = new FillFlowContainer - { - AutoSizeAxes = Axes.X, - Height = 30, - Direction = FillDirection.Horizontal, - LayoutDuration = transition_duration, - Spacing = new Vector2(5f, 0f), - Children = new Drawable[] - { - modeTypeInfo = new ModeTypeInfo(), - new Container - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Margin = new MarginPadding { Left = 5 }, - Children = new Drawable[] - { - beatmapTitle = new BeatmapTitle(), - beatmapAuthor = new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - TextSize = 14, - Colour = colours.Gray9, - }, - }, - }, - }, - }, + beatmapModeInfo = new BeatmapModeInfo(), }, }, }, @@ -255,26 +226,13 @@ namespace osu.Game.Screens.Multi.Components nameBind.ValueChanged += n => name.Text = n; hostBind.ValueChanged += h => participantInfo.Host = h; - typeBind.ValueChanged += t => modeTypeInfo.Type = t; + typeBind.ValueChanged += t => beatmapModeInfo.Type = t; statusBind.ValueChanged += displayStatus; beatmapBind.ValueChanged += b => { - modeTypeInfo.Beatmap = b; - - if (b != null) - { - cover.BeatmapSet = b.BeatmapSet; - beatmapTitle.Beatmap = b; - beatmapAuthor.Text = $"mapped by {b.Metadata.Author}"; - } - else - { - cover.BeatmapSet = null; - beatmapTitle.Beatmap = null; - - beatmapAuthor.Text = string.Empty; - } + cover.BeatmapSet = b?.BeatmapSet; + beatmapModeInfo.Beatmap = b; }; maxParticipantsBind.ValueChanged += m => @@ -325,7 +283,7 @@ namespace osu.Game.Screens.Multi.Components cover.BeatmapSet = null; participantsFlow.FadeOut(transition_duration); participantNumbersFlow.FadeOut(transition_duration); - infoPanelFlow.FadeOut(transition_duration); + beatmapModeInfo.FadeOut(transition_duration); name.FadeOut(transition_duration); participantInfo.FadeOut(transition_duration); @@ -335,7 +293,7 @@ namespace osu.Game.Screens.Multi.Components { participantsFlow.FadeIn(transition_duration); participantNumbersFlow.FadeIn(transition_duration); - infoPanelFlow.FadeIn(transition_duration); + beatmapModeInfo.FadeIn(transition_duration); name.FadeIn(transition_duration); participantInfo.FadeIn(transition_duration); From bd9af745dd898b770d7a8b7f1bc13b8641867dc5 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 23:36:35 -0300 Subject: [PATCH 17/70] Cleanup. (cherry picked from commit fffa6a004cf074caf0cf5c8ae1408a80500859fa) --- osu.Game/Screens/Multi/Components/ModeTypeInfo.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs index 26c391586a..e3aba685a7 100644 --- a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs @@ -55,8 +55,7 @@ namespace osu.Game.Screens.Multi.Components public ModeTypeInfo() { - AutoSizeAxes = Axes.X; - Height = height; + AutoSizeAxes = Axes.Both; Children = new[] { From dcc39d96e2801d29fa671d1963546855a6b53fbe Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 23:45:59 -0300 Subject: [PATCH 18/70] BeatmapModeInfo -> BeatmapTypeInfo. --- .../{BeatmapModeInfo.cs => BeatmapTypeInfo.cs} | 4 ++-- osu.Game/Screens/Multi/Components/ModeTypeInfo.cs | 1 + osu.Game/Screens/Multi/Components/RoomInspector.cs | 12 ++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) rename osu.Game/Screens/Multi/Components/{BeatmapModeInfo.cs => BeatmapTypeInfo.cs} (96%) diff --git a/osu.Game/Screens/Multi/Components/BeatmapModeInfo.cs b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs similarity index 96% rename from osu.Game/Screens/Multi/Components/BeatmapModeInfo.cs rename to osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs index 8bd7d7ea06..753006c62d 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapModeInfo.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs @@ -12,7 +12,7 @@ using OpenTK; namespace osu.Game.Screens.Multi.Components { - public class BeatmapModeInfo : FillFlowContainer + public class BeatmapTypeInfo : FillFlowContainer { private readonly ModeTypeInfo modeTypeInfo; private readonly BeatmapTitle beatmapTitle; @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Multi.Components set { modeTypeInfo.Type = value; } } - public BeatmapModeInfo() + public BeatmapTypeInfo() { AutoSizeAxes = Axes.Both; Direction = FillDirection.Horizontal; diff --git a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs index e3aba685a7..e2d0268090 100644 --- a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs @@ -64,6 +64,7 @@ namespace osu.Game.Screens.Multi.Components AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(5f, 0f), + LayoutDuration = 100, Children = new[] { rulesetContainer = new Container diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index c3b7d3a7ad..d9a35808a8 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -40,7 +40,7 @@ namespace osu.Game.Screens.Multi.Components private UpdateableBeatmapSetCover cover; private FillFlowContainer topFlow, participantsFlow, participantNumbersFlow; private OsuSpriteText name, status; - private BeatmapModeInfo beatmapModeInfo; + private BeatmapTypeInfo beatmapTypeInfo; private ScrollContainer participantsScroll; private ParticipantInfo participantInfo; @@ -188,7 +188,7 @@ namespace osu.Game.Screens.Multi.Components TextSize = 14, Font = @"Exo2.0-Bold", }, - beatmapModeInfo = new BeatmapModeInfo(), + beatmapTypeInfo = new BeatmapTypeInfo(), }, }, }, @@ -226,13 +226,13 @@ namespace osu.Game.Screens.Multi.Components nameBind.ValueChanged += n => name.Text = n; hostBind.ValueChanged += h => participantInfo.Host = h; - typeBind.ValueChanged += t => beatmapModeInfo.Type = t; + typeBind.ValueChanged += t => beatmapTypeInfo.Type = t; statusBind.ValueChanged += displayStatus; beatmapBind.ValueChanged += b => { cover.BeatmapSet = b?.BeatmapSet; - beatmapModeInfo.Beatmap = b; + beatmapTypeInfo.Beatmap = b; }; maxParticipantsBind.ValueChanged += m => @@ -283,7 +283,7 @@ namespace osu.Game.Screens.Multi.Components cover.BeatmapSet = null; participantsFlow.FadeOut(transition_duration); participantNumbersFlow.FadeOut(transition_duration); - beatmapModeInfo.FadeOut(transition_duration); + beatmapTypeInfo.FadeOut(transition_duration); name.FadeOut(transition_duration); participantInfo.FadeOut(transition_duration); @@ -293,7 +293,7 @@ namespace osu.Game.Screens.Multi.Components { participantsFlow.FadeIn(transition_duration); participantNumbersFlow.FadeIn(transition_duration); - beatmapModeInfo.FadeIn(transition_duration); + beatmapTypeInfo.FadeIn(transition_duration); name.FadeIn(transition_duration); participantInfo.FadeIn(transition_duration); From 7beac3a712138ec393b3cf84466f1742327d44b1 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 23:56:00 -0300 Subject: [PATCH 19/70] Cleanup DrawableRoom. --- osu.Game/Screens/Multi/Components/DrawableRoom.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs index 70adf8c7db..d31019a259 100644 --- a/osu.Game/Screens/Multi/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -227,18 +227,9 @@ namespace osu.Game.Screens.Multi.Components beatmapBind.ValueChanged += b => { + cover.BeatmapSet = b?.BeatmapSet; + beatmapTitle.Beatmap = b; modeTypeInfo.Beatmap = b; - - if (b != null) - { - cover.BeatmapSet = b.BeatmapSet; - beatmapTitle.Beatmap = b; - } - else - { - cover.BeatmapSet = null; - beatmapTitle.Beatmap = null; - } }; nameBind.BindTo(Room.Name); From 852d7ef48de64996af8fa109c8b4e8aedc0c5ec5 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 00:07:33 -0300 Subject: [PATCH 20/70] Use ?: expression instead of if/else. --- osu.Game/Screens/Multi/Components/BeatmapTitle.cs | 1 - osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs index a6cc472335..daa362409a 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs @@ -24,7 +24,6 @@ namespace osu.Game.Screens.Multi.Components private BeatmapInfo beatmap; public BeatmapInfo Beatmap { - get { return beatmap; } set { if (value == beatmap) return; diff --git a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs index 753006c62d..78ffe01ef0 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs @@ -23,11 +23,7 @@ namespace osu.Game.Screens.Multi.Components set { modeTypeInfo.Beatmap = beatmapTitle.Beatmap = value; - - if (value == null) - beatmapAuthor.Text = string.Empty; - else - beatmapAuthor.Text = $"mapped by {value.Metadata.Author}"; + beatmapAuthor.Text = value == null ? string.Empty : $"mapped by {value.Metadata.Author}"; } } From d090323c0039c1a39a58bb4f5a8aead177be9a99 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 00:51:56 -0300 Subject: [PATCH 21/70] Add ParticipantCount to share with the Match screen. --- .../Multi/Components/ParticipantCount.cs | 67 +++++++++++++++++++ .../Screens/Multi/Components/RoomInspector.cs | 52 ++------------ 2 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 osu.Game/Screens/Multi/Components/ParticipantCount.cs diff --git a/osu.Game/Screens/Multi/Components/ParticipantCount.cs b/osu.Game/Screens/Multi/Components/ParticipantCount.cs new file mode 100644 index 0000000000..96e2bd7bee --- /dev/null +++ b/osu.Game/Screens/Multi/Components/ParticipantCount.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Multi.Components +{ + public class ParticipantCount : FillFlowContainer + { + private const float text_size = 30; + private const float transition_duration = 100; + + private readonly OsuSpriteText count, slash, max; + + public int Count + { + set { count.Text = value.ToString(); } + } + + public int? Max + { + set + { + if (value == null) + { + slash.FadeOut(transition_duration); + max.FadeOut(transition_duration); + } + else + { + slash.FadeIn(transition_duration); + max.FadeIn(transition_duration); + max.Text = value.ToString(); + } + } + } + + public ParticipantCount() + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + LayoutDuration = transition_duration; + + Children = new[] + { + count = new OsuSpriteText + { + TextSize = text_size, + Font = @"Exo2.0-Bold" + }, + slash = new OsuSpriteText + { + Text = @"/", + TextSize = text_size, + Font = @"Exo2.0-Light" + }, + max = new OsuSpriteText + { + TextSize = text_size, + Font = @"Exo2.0-Light" + }, + }; + } + } +} diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index d9a35808a8..14f4feab05 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -38,7 +38,8 @@ namespace osu.Game.Screens.Multi.Components private OsuColour colours; private Box statusStrip; private UpdateableBeatmapSetCover cover; - private FillFlowContainer topFlow, participantsFlow, participantNumbersFlow; + private ParticipantCount participantCount; + private FillFlowContainer topFlow, participantsFlow; private OsuSpriteText name, status; private BeatmapTypeInfo beatmapTypeInfo; private ScrollContainer participantsScroll; @@ -81,9 +82,6 @@ namespace osu.Game.Screens.Multi.Components { this.colours = colours; - ModeTypeInfo modeTypeInfo; - OsuSpriteText participants, participantsSlash, maxParticipants, beatmapAuthor; - Children = new Drawable[] { new Box @@ -120,32 +118,10 @@ namespace osu.Game.Screens.Multi.Components Padding = new MarginPadding(20), Children = new Drawable[] { - participantNumbersFlow = new FillFlowContainer + participantCount = new ParticipantCount { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - LayoutDuration = transition_duration, - Children = new[] - { - participants = new OsuSpriteText - { - TextSize = 30, - Font = @"Exo2.0-Bold" - }, - participantsSlash = new OsuSpriteText - { - Text = @"/", - TextSize = 30, - Font = @"Exo2.0-Light" - }, - maxParticipants = new OsuSpriteText - { - TextSize = 30, - Font = @"Exo2.0-Light" - }, - }, }, name = new OsuSpriteText { @@ -227,6 +203,7 @@ namespace osu.Game.Screens.Multi.Components nameBind.ValueChanged += n => name.Text = n; hostBind.ValueChanged += h => participantInfo.Host = h; typeBind.ValueChanged += t => beatmapTypeInfo.Type = t; + maxParticipantsBind.ValueChanged += m => participantCount.Max = m; statusBind.ValueChanged += displayStatus; beatmapBind.ValueChanged += b => @@ -235,24 +212,9 @@ namespace osu.Game.Screens.Multi.Components beatmapTypeInfo.Beatmap = b; }; - maxParticipantsBind.ValueChanged += m => - { - if (m == null) - { - participantsSlash.FadeOut(transition_duration); - maxParticipants.FadeOut(transition_duration); - } - else - { - participantsSlash.FadeIn(transition_duration); - maxParticipants.FadeIn(transition_duration); - maxParticipants.Text = m.ToString(); - } - }; - participantsBind.ValueChanged += p => { - participants.Text = p.Length.ToString(); + participantCount.Count = p.Length; participantInfo.Participants = p; participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u)); }; @@ -282,7 +244,7 @@ namespace osu.Game.Screens.Multi.Components { cover.BeatmapSet = null; participantsFlow.FadeOut(transition_duration); - participantNumbersFlow.FadeOut(transition_duration); + participantCount.FadeOut(transition_duration); beatmapTypeInfo.FadeOut(transition_duration); name.FadeOut(transition_duration); participantInfo.FadeOut(transition_duration); @@ -292,7 +254,7 @@ namespace osu.Game.Screens.Multi.Components else { participantsFlow.FadeIn(transition_duration); - participantNumbersFlow.FadeIn(transition_duration); + participantCount.FadeIn(transition_duration); beatmapTypeInfo.FadeIn(transition_duration); name.FadeIn(transition_duration); participantInfo.FadeIn(transition_duration); From 4f73f6e0e02a62bfa6a10f0d2053a0c38ac2cc8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 29 May 2018 08:18:54 +0200 Subject: [PATCH 22/70] Add build tasks for visual tests and fix broken launch tasks --- .vscode/launch.json | 10 +++++----- .vscode/tasks.json | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index df5b11f63a..11141dc182 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -66,7 +66,7 @@ "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll" ], "cwd": "${workspaceRoot}", - "preLaunchTask": "Build (Debug, dotnet)", + "preLaunchTask": "Build tests (Debug, dotnet)", "env": {}, "console": "internalConsole" }, @@ -76,10 +76,10 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll" + "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.0/osu.Game.Tests.dll" ], "cwd": "${workspaceRoot}", - "preLaunchTask": "Build (Release, dotnet)", + "preLaunchTask": "Build tests (Release, dotnet)", "env": {}, "console": "internalConsole" }, @@ -92,7 +92,7 @@ "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll", ], "cwd": "${workspaceRoot}", - "preLaunchTask": "Build (Debug, dotnet)", + "preLaunchTask": "Build osu! (Debug, dotnet)", "env": {}, "console": "internalConsole" }, @@ -105,7 +105,7 @@ "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll", ], "cwd": "${workspaceRoot}", - "preLaunchTask": "Build (Release, dotnet)", + "preLaunchTask": "Build osu! (Release, dotnet)", "env": {}, "console": "internalConsole" } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7144a584f3..0908ff6108 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -31,7 +31,7 @@ "problemMatcher": "$msCompile" }, { - "label": "Build (Debug, dotnet)", + "label": "Build osu! (Debug, dotnet)", "type": "shell", "command": "dotnet", "args": [ @@ -47,7 +47,7 @@ "problemMatcher": "$msCompile" }, { - "label": "Build (Release, dotnet)", + "label": "Build osu! (Release, dotnet)", "type": "shell", "command": "dotnet", "args": [ @@ -63,6 +63,39 @@ "group": "build", "problemMatcher": "$msCompile" }, + { + "label": "Build tests (Debug, dotnet)", + "type": "shell", + "command": "dotnet", + "args": [ + "build", + "--no-restore", + "osu.Game.Tests", + "/p:TargetFramework=netcoreapp2.0", + "/p:GenerateFullPaths=true", + "/m", + "/verbosity:m" + ], + "group": "build", + "problemMatcher": "$msCompile" + }, + { + "label": "Build tests (Release, dotnet)", + "type": "shell", + "command": "dotnet", + "args": [ + "build", + "--no-restore", + "osu.Game.Tests", + "/p:TargetFramework=netcoreapp2.0", + "/p:Configuration=Release", + "/p:GenerateFullPaths=true", + "/m", + "/verbosity:m" + ], + "group": "build", + "problemMatcher": "$msCompile" + }, { "label": "Restore (net471)", "type": "shell", From 2a87b851fae5d3fb783c936782155968006f1900 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 28 May 2018 18:38:42 +0900 Subject: [PATCH 23/70] Add proper transaction rollback logic on exception --- osu.Game/Database/DatabaseWriteUsage.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/DatabaseWriteUsage.cs b/osu.Game/Database/DatabaseWriteUsage.cs index 7858c1a0d1..07bebbf0c3 100644 --- a/osu.Game/Database/DatabaseWriteUsage.cs +++ b/osu.Game/Database/DatabaseWriteUsage.cs @@ -28,8 +28,19 @@ namespace osu.Game.Database if (isDisposed) return; isDisposed = true; - PerformedWrite |= Context.SaveChanges(transaction) > 0; - usageCompleted?.Invoke(this); + try + { + PerformedWrite |= Context.SaveChanges(transaction) > 0; + } + catch (Exception e) + { + transaction?.Rollback(); + throw; + } + finally + { + usageCompleted?.Invoke(this); + } } public void Dispose() From d4e7f08c20ce4311e9dba4ff1a6feade891d50aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 28 May 2018 18:43:53 +0900 Subject: [PATCH 24/70] Bring entity framework up-to-date and re-enable transactions --- osu.Desktop/osu.Desktop.csproj | 6 +++--- osu.Game/Database/OsuDbContext.cs | 3 +-- osu.Game/osu.Game.csproj | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 3d64cab84e..3a35568f8f 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -1,4 +1,4 @@ - + net471;netcoreapp2.0 @@ -30,10 +30,10 @@ - + - + \ No newline at end of file diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 1979ce3648..06503ffc5f 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -106,8 +106,7 @@ namespace osu.Game.Database public IDbContextTransaction BeginTransaction() { - // return Database.BeginTransaction(); - return null; + return Database.BeginTransaction(); } public int SaveChanges(IDbContextTransaction transaction = null) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1a75f1979a..afb656a260 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -17,7 +17,7 @@ - + From bcb04f616895f166cdfff223e781d11dda77aba0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 28 May 2018 19:56:27 +0900 Subject: [PATCH 25/70] Improve transaction handling flexibility --- osu.Game/Database/ArchiveModelManager.cs | 66 +++++++++++++++++---- osu.Game/Database/DatabaseContextFactory.cs | 23 ++++++- osu.Game/Database/DatabaseWriteUsage.cs | 16 +++-- osu.Game/Database/OsuDbContext.cs | 13 ---- 4 files changed, 84 insertions(+), 34 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index e04559d547..28c25c873f 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -56,13 +56,42 @@ namespace osu.Game.Database // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ArchiveImportIPCChannel ipc; + private readonly List cachedEvents = new List(); + + private bool delayingEvents; + + private void cacheEvents() + { + delayingEvents = true; + } + + private void flushEvents(bool perform) + { + if (perform) + { + foreach (var a in cachedEvents) + a.Invoke(); + } + + cachedEvents.Clear(); + delayingEvents = false; + } + + private void handleEvent(Action a) + { + if (delayingEvents) + cachedEvents.Add(a); + else + a.Invoke(); + } + protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStore modelStore, IIpcHost importHost = null) { ContextFactory = contextFactory; ModelStore = modelStore; - ModelStore.ItemAdded += s => ItemAdded?.Invoke(s); - ModelStore.ItemRemoved += s => ItemRemoved?.Invoke(s); + ModelStore.ItemAdded += s => handleEvent(() => ItemAdded?.Invoke(s)); + ModelStore.ItemRemoved += s => handleEvent(() => ItemRemoved?.Invoke(s)); Files = new FileStore(contextFactory, storage); @@ -138,24 +167,37 @@ namespace osu.Game.Database /// The archive to be imported. public TModel Import(ArchiveReader archive) { - using (ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes. + TModel item = null; + cacheEvents(); + + try { - // create a new model (don't yet add to database) - var item = CreateModel(archive); + using (var write = ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes. + { + if (!write.IsTransactionLeader) throw new InvalidOperationException($"Ensure there is no parent transaction so errors can correctly be handled by {this}"); - var existing = CheckForExisting(item); + // create a new model (don't yet add to database) + item = CreateModel(archive); - if (existing != null) return existing; + var existing = CheckForExisting(item); - item.Files = createFileInfos(archive, Files); + if (existing != null) return existing; - Populate(item, archive); + item.Files = createFileInfos(archive, Files); - // import to store - ModelStore.Add(item); + Populate(item, archive); - return item; + // import to store + ModelStore.Add(item); + } } + catch + { + item = null; + } + + flushEvents(item != null); + return item; } /// diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 71960303b5..65a19e23c0 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -1,7 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using System.Threading; +using Microsoft.EntityFrameworkCore.Storage; using osu.Framework.Platform; namespace osu.Game.Database @@ -17,8 +19,12 @@ namespace osu.Game.Database private readonly object writeLock = new object(); private bool currentWriteDidWrite; + private bool currentWriteDidError; + private int currentWriteUsages; + private IDbContextTransaction currentWriteTransaction; + public DatabaseContextFactory(GameHost host) { this.host = host; @@ -40,9 +46,12 @@ namespace osu.Game.Database { Monitor.Enter(writeLock); + if (currentWriteTransaction == null) + currentWriteTransaction = threadContexts.Value.Database.BeginTransaction(); + Interlocked.Increment(ref currentWriteUsages); - return new DatabaseWriteUsage(threadContexts.Value, usageCompleted); + return new DatabaseWriteUsage(threadContexts.Value, usageCompleted) { IsTransactionLeader = currentWriteUsages == 1 }; } private void usageCompleted(DatabaseWriteUsage usage) @@ -52,16 +61,24 @@ namespace osu.Game.Database try { currentWriteDidWrite |= usage.PerformedWrite; + currentWriteDidError |= usage.Errors.Any(); if (usages > 0) return; + if (currentWriteDidError) + currentWriteTransaction.Rollback(); + else + currentWriteTransaction.Commit(); + + currentWriteTransaction = null; + currentWriteDidWrite = false; + currentWriteDidError = false; + if (currentWriteDidWrite) { // explicitly dispose to ensure any outstanding flushes happen as soon as possible (and underlying resources are purged). usage.Context.Dispose(); - currentWriteDidWrite = false; - // once all writes are complete, we want to refresh thread-specific contexts to make sure they don't have stale local caches. recycleThreadContexts(); } diff --git a/osu.Game/Database/DatabaseWriteUsage.cs b/osu.Game/Database/DatabaseWriteUsage.cs index 07bebbf0c3..8216c04b22 100644 --- a/osu.Game/Database/DatabaseWriteUsage.cs +++ b/osu.Game/Database/DatabaseWriteUsage.cs @@ -2,26 +2,31 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using Microsoft.EntityFrameworkCore.Storage; +using System.Collections.Generic; namespace osu.Game.Database { public class DatabaseWriteUsage : IDisposable { public readonly OsuDbContext Context; - private readonly IDbContextTransaction transaction; private readonly Action usageCompleted; public DatabaseWriteUsage(OsuDbContext context, Action onCompleted) { Context = context; - transaction = Context.BeginTransaction(); usageCompleted = onCompleted; } public bool PerformedWrite { get; private set; } private bool isDisposed; + public List Errors = new List(); + + /// + /// Whether this write usage will commit a transaction on completion. + /// If false, there is a parent usage responsible for transaction commit. + /// + public bool IsTransactionLeader = false; protected void Dispose(bool disposing) { @@ -30,12 +35,11 @@ namespace osu.Game.Database try { - PerformedWrite |= Context.SaveChanges(transaction) > 0; + PerformedWrite |= Context.SaveChanges() > 0; } catch (Exception e) { - transaction?.Rollback(); - throw; + Errors.Add(e); } finally { diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 06503ffc5f..0ae197d62d 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -3,7 +3,6 @@ using System; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Logging; using osu.Framework.Logging; @@ -104,18 +103,6 @@ namespace osu.Game.Database modelBuilder.Entity().HasOne(b => b.BaseDifficulty); } - public IDbContextTransaction BeginTransaction() - { - return Database.BeginTransaction(); - } - - public int SaveChanges(IDbContextTransaction transaction = null) - { - var ret = base.SaveChanges(); - if (ret > 0) transaction?.Commit(); - return ret; - } - private class OsuDbLoggerFactory : ILoggerFactory { #region Disposal From 7b8211e6db51cd8b1d9a43f2172b55fd974c8a73 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 04:23:29 -0300 Subject: [PATCH 26/70] Add MultiplayerScreen.Type --- osu.Game/Screens/Multi/Header.cs | 8 ++++---- osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs | 3 ++- osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs | 5 +++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Multi/Header.cs b/osu.Game/Screens/Multi/Header.cs index de71b20007..fb4da45aca 100644 --- a/osu.Game/Screens/Multi/Header.cs +++ b/osu.Game/Screens/Multi/Header.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Multi { public const float HEIGHT = 121; - private readonly OsuSpriteText screenTitle; + private readonly OsuSpriteText screenType; private readonly HeaderBreadcrumbControl breadcrumbs; public Header(Screen initialScreen) @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Multi Text = "multiplayer ", TextSize = 25, }, - screenTitle = new OsuSpriteText + screenType = new OsuSpriteText { TextSize = 25, Font = @"Exo2.0-Light", @@ -86,14 +86,14 @@ namespace osu.Game.Screens.Multi }, }; - breadcrumbs.Current.ValueChanged += s => screenTitle.Text = ((MultiplayerScreen)s).Title; + breadcrumbs.Current.ValueChanged += s => screenType.Text = ((MultiplayerScreen)s).Type; breadcrumbs.Current.TriggerChange(); } [BackgroundDependencyLoader] private void load(OsuColour colours) { - screenTitle.Colour = colours.Yellow; + screenType.Colour = colours.Yellow; breadcrumbs.StripColour = colours.Green; } diff --git a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs index 60ffe2c0b9..f0c93b1146 100644 --- a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs +++ b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs @@ -25,7 +25,8 @@ namespace osu.Game.Screens.Multi.Screens.Lounge protected readonly FillFlowContainer RoomsContainer; protected readonly RoomInspector Inspector; - public override string Title => "lounge"; + public override string Type => "lounge"; + public override string Title => "Lounge"; protected override Container TransitionContent => content; diff --git a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs index 191fe66037..cdfa17a7a6 100644 --- a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs +++ b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs @@ -15,6 +15,11 @@ namespace osu.Game.Screens.Multi.Screens protected virtual Container TransitionContent => Content; + /// + /// The type to display in the title of the . + /// + public abstract string Type { get; } + protected override void OnEntering(Screen last) { base.OnEntering(last); From a3287b8cf2e3734e606b20490c9f2f8d5ab4a962 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 28 May 2018 21:45:05 +0900 Subject: [PATCH 27/70] Correctly rollback failed imports --- osu.Game/Database/ArchiveModelManager.cs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 28c25c873f..86af2fd0ed 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -58,13 +58,20 @@ namespace osu.Game.Database private readonly List cachedEvents = new List(); + /// + /// Allows delaying of outwards events until an operation is confirmed (at a database level). + /// private bool delayingEvents; - private void cacheEvents() - { - delayingEvents = true; - } + /// + /// Begin delaying outwards events. + /// + private void delayEvents() => delayingEvents = true; + /// + /// Flush delayed events and disable delaying. + /// + /// Whether the flushed events should be performed. private void flushEvents(bool perform) { if (perform) @@ -167,8 +174,8 @@ namespace osu.Game.Database /// The archive to be imported. public TModel Import(ArchiveReader archive) { - TModel item = null; - cacheEvents(); + TModel item; + delayEvents(); try { @@ -196,6 +203,7 @@ namespace osu.Game.Database item = null; } + // we only want to flush events after we've confirmed the write context didn't have any errors. flushEvents(item != null); return item; } From 80806be0471d1547e4b6af8b7b6f2ec520e780f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 10:59:39 +0900 Subject: [PATCH 28/70] Don't start transactions for migration It looks like transactions are used internally during migration. --- osu.Game/Database/DatabaseContextFactory.cs | 11 ++++++----- osu.Game/Database/IDatabaseContextFactory.cs | 3 ++- osu.Game/Database/SingletonContextFactory.cs | 2 +- osu.Game/OsuGameBase.cs | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 65a19e23c0..ec408456e3 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -41,17 +41,18 @@ namespace osu.Game.Database /// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context). /// This method may block if a write is already active on a different thread. /// + /// Whether to start a transaction for this write. /// A usage containing a usable context. - public DatabaseWriteUsage GetForWrite() + public DatabaseWriteUsage GetForWrite(bool withTransaction = true) { Monitor.Enter(writeLock); - if (currentWriteTransaction == null) + if (currentWriteTransaction == null && withTransaction) currentWriteTransaction = threadContexts.Value.Database.BeginTransaction(); Interlocked.Increment(ref currentWriteUsages); - return new DatabaseWriteUsage(threadContexts.Value, usageCompleted) { IsTransactionLeader = currentWriteUsages == 1 }; + return new DatabaseWriteUsage(threadContexts.Value, usageCompleted) { IsTransactionLeader = currentWriteTransaction != null && currentWriteUsages == 1 }; } private void usageCompleted(DatabaseWriteUsage usage) @@ -66,9 +67,9 @@ namespace osu.Game.Database if (usages > 0) return; if (currentWriteDidError) - currentWriteTransaction.Rollback(); + currentWriteTransaction?.Rollback(); else - currentWriteTransaction.Commit(); + currentWriteTransaction?.Commit(); currentWriteTransaction = null; currentWriteDidWrite = false; diff --git a/osu.Game/Database/IDatabaseContextFactory.cs b/osu.Game/Database/IDatabaseContextFactory.cs index 372e1770e4..d38d15b252 100644 --- a/osu.Game/Database/IDatabaseContextFactory.cs +++ b/osu.Game/Database/IDatabaseContextFactory.cs @@ -14,7 +14,8 @@ namespace osu.Game.Database /// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context). /// This method may block if a write is already active on a different thread. /// + /// Whether to start a transaction for this write. /// A usage containing a usable context. - DatabaseWriteUsage GetForWrite(); + DatabaseWriteUsage GetForWrite(bool withTransaction = true); } } diff --git a/osu.Game/Database/SingletonContextFactory.cs b/osu.Game/Database/SingletonContextFactory.cs index 74951e8433..ce3fbf6881 100644 --- a/osu.Game/Database/SingletonContextFactory.cs +++ b/osu.Game/Database/SingletonContextFactory.cs @@ -14,6 +14,6 @@ namespace osu.Game.Database public OsuDbContext Get() => context; - public DatabaseWriteUsage GetForWrite() => new DatabaseWriteUsage(context, null); + public DatabaseWriteUsage GetForWrite(bool withTransaction = true) => new DatabaseWriteUsage(context, null); } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index a3a081d6d1..b9d32a6322 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -208,7 +208,7 @@ namespace osu.Game { try { - using (var db = contextFactory.GetForWrite()) + using (var db = contextFactory.GetForWrite(false)) db.Context.Migrate(); } catch (MigrationFailedException e) @@ -220,7 +220,7 @@ namespace osu.Game contextFactory.ResetDatabase(); Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important); - using (var db = contextFactory.GetForWrite()) + using (var db = contextFactory.GetForWrite(false)) db.Context.Migrate(); } } From 72da640059e8aa05f193d0d3800bc0d6fee50cf6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 11:37:47 +0900 Subject: [PATCH 29/70] Change order of event firing in Update calls A remove event should not be fired before the update is successful. --- osu.Game/Database/MutableDatabaseBackedStore.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Database/MutableDatabaseBackedStore.cs b/osu.Game/Database/MutableDatabaseBackedStore.cs index 8569d81f01..69a1f57cc4 100644 --- a/osu.Game/Database/MutableDatabaseBackedStore.cs +++ b/osu.Game/Database/MutableDatabaseBackedStore.cs @@ -50,11 +50,10 @@ namespace osu.Game.Database /// The item to update. public void Update(T item) { - ItemRemoved?.Invoke(item); - using (var usage = ContextFactory.GetForWrite()) usage.Context.Update(item); + ItemRemoved?.Invoke(item); ItemAdded?.Invoke(item); } From 015fd9d0e7d256410dea6fe583b3e5e7c0043a02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 11:44:42 +0900 Subject: [PATCH 30/70] Fix loading test method returning oldest import rather than newest --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index f60caf2397..740692395a 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Beatmaps.IO waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000); - return imported.FirstOrDefault(); + return imported.LastOrDefault(); } private void deleteBeatmapSet(BeatmapSetInfo imported, OsuGameBase osu) From cc081cad5a0d78367420b31bfdb8b7a2baff0686 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 11:57:11 +0900 Subject: [PATCH 31/70] Simplify test osz instantiation --- .../Beatmaps/IO/ImportBeatmapTest.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 740692395a..38fd6e649b 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -162,8 +162,7 @@ namespace osu.Game.Tests.Beatmaps.IO var osu = loadOsu(host); - var temp = prepareTempCopy(osz_path); - Assert.IsTrue(File.Exists(temp)); + var temp = createTemporaryBeatmap(); var importer = new ArchiveImportIPCChannel(client); if (!importer.ImportAsync(temp).Wait(10000)) @@ -188,8 +187,7 @@ namespace osu.Game.Tests.Beatmaps.IO try { var osu = loadOsu(host); - var temp = prepareTempCopy(osz_path); - Assert.IsTrue(File.Exists(temp), "Temporary file copy never substantiated"); + var temp = createTemporaryBeatmap(); using (File.OpenRead(temp)) osu.Dependencies.Get().Import(temp); ensureLoaded(osu); @@ -203,11 +201,16 @@ namespace osu.Game.Tests.Beatmaps.IO } } - private BeatmapSetInfo loadOszIntoOsu(OsuGameBase osu) + private string createTemporaryBeatmap() { - var temp = prepareTempCopy(osz_path); - + var temp = new FileInfo(osz_path).CopyTo(Path.GetTempFileName(), true).FullName; Assert.IsTrue(File.Exists(temp)); + return temp; + } + + private BeatmapSetInfo loadOszIntoOsu(OsuGameBase osu, string path = null) + { + var temp = path ?? createTemporaryBeatmap(); var manager = osu.Dependencies.Get(); @@ -232,12 +235,6 @@ namespace osu.Game.Tests.Beatmaps.IO Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending); } - private string prepareTempCopy(string path) - { - var temp = Path.GetTempFileName(); - return new FileInfo(path).CopyTo(temp, true).FullName; - } - private OsuGameBase loadOsu(GameHost host) { var osu = new OsuGameBase(); From 3d3026a80cdce1dc15f04b88f242120ec09cfffc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 13:48:14 +0900 Subject: [PATCH 32/70] Report any error during import to the write context to allow for rollback --- osu.Game/Database/ArchiveModelManager.cs | 26 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 86af2fd0ed..99f1e9f581 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -181,21 +181,29 @@ namespace osu.Game.Database { using (var write = ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes. { - if (!write.IsTransactionLeader) throw new InvalidOperationException($"Ensure there is no parent transaction so errors can correctly be handled by {this}"); + try + { + if (!write.IsTransactionLeader) throw new InvalidOperationException($"Ensure there is no parent transaction so errors can correctly be handled by {this}"); - // create a new model (don't yet add to database) - item = CreateModel(archive); + // create a new model (don't yet add to database) + item = CreateModel(archive); - var existing = CheckForExisting(item); + var existing = CheckForExisting(item); - if (existing != null) return existing; + if (existing != null) return existing; - item.Files = createFileInfos(archive, Files); + item.Files = createFileInfos(archive, Files); - Populate(item, archive); + Populate(item, archive); - // import to store - ModelStore.Add(item); + // import to store + ModelStore.Add(item); + } + catch (Exception e) + { + write.Errors.Add(e); + throw; + } } } catch From 203691b1c776728fb48564c51bef60a20bc0d499 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 13:48:27 +0900 Subject: [PATCH 33/70] Add import rollback test --- .../Beatmaps/IO/ImportBeatmapTest.cs | 75 +++++++++++++++++-- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 38fd6e649b..586217a05f 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -12,6 +12,7 @@ using osu.Framework.Platform; using osu.Game.IPC; using osu.Framework.Allocation; using osu.Game.Beatmaps; +using SharpCompress.Archives.Zip; namespace osu.Game.Tests.Beatmaps.IO { @@ -77,8 +78,69 @@ namespace osu.Game.Tests.Beatmaps.IO var manager = osu.Dependencies.Get(); - Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 1); - Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1); + Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count); + Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count); + } + finally + { + host.Exit(); + } + } + } + + [Test] + public void TestRollbackOnFailure() + { + //unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here. + using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestRollbackOnFailure")) + { + try + { + var osu = loadOsu(host); + var manager = osu.Dependencies.Get(); + + int fireCount = 0; + + // ReSharper disable once AccessToModifiedClosure + manager.ItemAdded += _ => fireCount++; + manager.ItemRemoved += _ => fireCount++; + + var imported = loadOszIntoOsu(osu); + + Assert.AreEqual(0, fireCount -= 1); + + imported.Hash += "-changed"; + manager.Update(imported); + + Assert.AreEqual(0, fireCount -= 2); + + var breakTemp = createTemporaryBeatmap(); + + MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 }); + MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp)); + + File.Delete(breakTemp); + + using (var outStream = File.Open(breakTemp, FileMode.CreateNew)) + using (var zip = ZipArchive.Open(brokenOsz)) + { + zip.AddEntry("broken.osu", brokenOsu, false); + zip.SaveTo(outStream, SharpCompress.Common.CompressionType.Deflate); + } + + Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count); + Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count); + Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count); + + // this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu. + manager.Import(breakTemp); + + // no events should be fired in the case of a rollback. + Assert.AreEqual(0, fireCount); + + Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count); + Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count); + Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count); } finally { @@ -100,18 +162,17 @@ namespace osu.Game.Tests.Beatmaps.IO var imported = loadOszIntoOsu(osu); - //var change = manager.QueryBeatmapSets(_ => true).First(); imported.Hash += "-changed"; manager.Update(imported); var importedSecondTime = loadOszIntoOsu(osu); - // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. Assert.IsTrue(imported.ID != importedSecondTime.ID); Assert.IsTrue(imported.Beatmaps.First().ID < importedSecondTime.Beatmaps.First().ID); - Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 1); - Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1); + // only one beatmap will exist as the online set ID matched, causing purging of the first import. + Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count); + Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count); } finally { @@ -231,7 +292,7 @@ namespace osu.Game.Tests.Beatmaps.IO manager.Delete(imported); Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 0); - Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1); + Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count); Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending); } From c1f416b1ccb6cea656d90c128c120048d9619a81 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 14:25:27 +0900 Subject: [PATCH 34/70] Add back missing rethrow --- osu.Game/Database/DatabaseWriteUsage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Database/DatabaseWriteUsage.cs b/osu.Game/Database/DatabaseWriteUsage.cs index 8216c04b22..64ab24e824 100644 --- a/osu.Game/Database/DatabaseWriteUsage.cs +++ b/osu.Game/Database/DatabaseWriteUsage.cs @@ -40,6 +40,7 @@ namespace osu.Game.Database catch (Exception e) { Errors.Add(e); + throw; } finally { From de8c4e6d564da5f2cc4aa55518cd8210985260c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 16:13:02 +0900 Subject: [PATCH 35/70] Remove unique constraints on hash columns We are going to allow multiple instances of the same beatmap info hash as they could be in different beatmap sets. --- osu.Game/Database/OsuDbContext.cs | 4 +- ...54_RemoveUniqueHashConstraints.Designer.cs | 377 ++++++++++++++++++ ...80529055154_RemoveUniqueHashConstraints.cs | 53 +++ .../Migrations/OsuDbContextModelSnapshot.cs | 16 +- 4 files changed, 441 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs create mode 100644 osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 0ae197d62d..7758b3eb25 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -82,8 +82,8 @@ namespace osu.Game.Database base.OnModelCreating(modelBuilder); modelBuilder.Entity().HasIndex(b => b.OnlineBeatmapID).IsUnique(); - modelBuilder.Entity().HasIndex(b => b.MD5Hash).IsUnique(); - modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); + modelBuilder.Entity().HasIndex(b => b.MD5Hash); + modelBuilder.Entity().HasIndex(b => b.Hash); modelBuilder.Entity().HasIndex(b => b.OnlineBeatmapSetID).IsUnique(); modelBuilder.Entity().HasIndex(b => b.DeletePending); diff --git a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs new file mode 100644 index 0000000000..f28408bfb3 --- /dev/null +++ b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs @@ -0,0 +1,377 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using osu.Game.Database; +using System; + +namespace osu.Game.Migrations +{ + [DbContext(typeof(OsuDbContext))] + [Migration("20180529055154_RemoveUniqueHashConstraints")] + partial class RemoveUniqueHashConstraints + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.3-rtm-10026"); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("ApproachRate"); + + b.Property("CircleSize"); + + b.Property("DrainRate"); + + b.Property("OverallDifficulty"); + + b.Property("SliderMultiplier"); + + b.Property("SliderTickRate"); + + b.HasKey("ID"); + + b.ToTable("BeatmapDifficulty"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("AudioLeadIn"); + + b.Property("BaseDifficultyID"); + + b.Property("BeatDivisor"); + + b.Property("BeatmapSetInfoID"); + + b.Property("Countdown"); + + b.Property("DistanceSpacing"); + + b.Property("GridSize"); + + b.Property("Hash"); + + b.Property("Hidden"); + + b.Property("LetterboxInBreaks"); + + b.Property("MD5Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + + b.Property("Path"); + + b.Property("RulesetID"); + + b.Property("SpecialStyle"); + + b.Property("StackLeniency"); + + b.Property("StarDifficulty"); + + b.Property("StoredBookmarks"); + + b.Property("TimelineZoom"); + + b.Property("Version"); + + b.Property("WidescreenStoryboard"); + + b.HasKey("ID"); + + b.HasIndex("BaseDifficultyID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("Hash"); + + b.HasIndex("MD5Hash"); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("BeatmapInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Artist"); + + b.Property("ArtistUnicode"); + + b.Property("AudioFile"); + + b.Property("AuthorString") + .HasColumnName("Author"); + + b.Property("BackgroundFile"); + + b.Property("PreviewTime"); + + b.Property("Source"); + + b.Property("Tags"); + + b.Property("Title"); + + b.Property("TitleUnicode"); + + b.HasKey("ID"); + + b.ToTable("BeatmapMetadata"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("BeatmapSetInfoID"); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("FileInfoID"); + + b.ToTable("BeatmapSetFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapSetID"); + + b.Property("Protected"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapSetID") + .IsUnique(); + + b.ToTable("BeatmapSetInfo"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntKey") + .HasColumnName("Key"); + + b.Property("RulesetID"); + + b.Property("StringValue") + .HasColumnName("Value"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntAction") + .HasColumnName("Action"); + + b.Property("KeysString") + .HasColumnName("Keys"); + + b.Property("RulesetID"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("IntAction"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("KeyBinding"); + }); + + modelBuilder.Entity("osu.Game.IO.FileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Hash"); + + b.Property("ReferenceCount"); + + b.HasKey("ID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("ReferenceCount"); + + b.ToTable("FileInfo"); + }); + + modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Available"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.Property("ShortName"); + + b.HasKey("ID"); + + b.HasIndex("Available"); + + b.HasIndex("ShortName") + .IsUnique(); + + b.ToTable("RulesetInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("SkinInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("SkinInfoID"); + + b.ToTable("SkinFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Creator"); + + b.Property("DeletePending"); + + b.Property("Name"); + + b.HasKey("ID"); + + b.ToTable("SkinInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") + .WithMany("Beatmaps") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithMany("Files") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Files") + .HasForeignKey("SkinInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs new file mode 100644 index 0000000000..fe8c983a3f --- /dev/null +++ b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs @@ -0,0 +1,53 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace osu.Game.Migrations +{ + public partial class RemoveUniqueHashConstraints : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_BeatmapInfo_Hash", + table: "BeatmapInfo"); + + migrationBuilder.DropIndex( + name: "IX_BeatmapInfo_MD5Hash", + table: "BeatmapInfo"); + + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_Hash", + table: "BeatmapInfo", + column: "Hash"); + + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_MD5Hash", + table: "BeatmapInfo", + column: "MD5Hash"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_BeatmapInfo_Hash", + table: "BeatmapInfo"); + + migrationBuilder.DropIndex( + name: "IX_BeatmapInfo_MD5Hash", + table: "BeatmapInfo"); + + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_Hash", + table: "BeatmapInfo", + column: "Hash", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_MD5Hash", + table: "BeatmapInfo", + column: "MD5Hash", + unique: true); + } + } +} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 2abbe7785f..d750d50b5b 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -1,7 +1,11 @@ // using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; using osu.Game.Database; +using System; namespace osu.Game.Migrations { @@ -12,7 +16,7 @@ namespace osu.Game.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + .HasAnnotation("ProductVersion", "2.0.3-rtm-10026"); modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => { @@ -27,9 +31,9 @@ namespace osu.Game.Migrations b.Property("OverallDifficulty"); - b.Property("SliderMultiplier"); + b.Property("SliderMultiplier"); - b.Property("SliderTickRate"); + b.Property("SliderTickRate"); b.HasKey("ID"); @@ -91,11 +95,9 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); - b.HasIndex("Hash") - .IsUnique(); + b.HasIndex("Hash"); - b.HasIndex("MD5Hash") - .IsUnique(); + b.HasIndex("MD5Hash"); b.HasIndex("MetadataID"); From 47d88a48a246064a753499882cbc07e1ed721250 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 16:14:09 +0900 Subject: [PATCH 36/70] Add logging on import processes --- osu.Game/Beatmaps/BeatmapManager.cs | 3 ++- osu.Game/Database/ArchiveModelManager.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 36fde8a319..b7bece9492 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -107,6 +107,7 @@ namespace osu.Game.Beatmaps { Delete(existingOnlineId); beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); + Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); } } @@ -303,7 +304,7 @@ namespace osu.Game.Beatmaps { // let's make sure there are actually .osu files to import. string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu")); - if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in the map folder."); + if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in this beatmap archive."); BeatmapMetadata metadata; using (var stream = new StreamReader(reader.GetStream(mapName))) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 99f1e9f581..74c7b3df5d 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -190,7 +190,11 @@ namespace osu.Game.Database var existing = CheckForExisting(item); - if (existing != null) return existing; + if (existing != null) + { + Logger.Log($"Found existing {typeof(TModel)} for {archive.Name} (ID {existing.ID}). Skipping import.", LoggingTarget.Database); + return existing; + } item.Files = createFileInfos(archive, Files); @@ -205,9 +209,12 @@ namespace osu.Game.Database throw; } } + + Logger.Log($"Import of {archive.Name} successfully completed!", LoggingTarget.Database); } catch { + Logger.Log($"Import of {archive.Name} failed and has been rolled back.", LoggingTarget.Database); item = null; } From 0adc16f9bd4836030dde06cae1248d35a07f384f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 16:15:44 +0900 Subject: [PATCH 37/70] Handle online ID mismatches and clashes on beatmap import --- osu.Game/Beatmaps/BeatmapManager.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index b7bece9492..abc0351a82 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -81,7 +81,7 @@ namespace osu.Game.Beatmaps protected override void Populate(BeatmapSetInfo model, ArchiveReader archive) { - model.Beatmaps = createBeatmapDifficulties(archive); + model.Beatmaps = createBeatmapDifficulties(model, archive); // remove metadata from difficulties where it matches the set foreach (BeatmapInfo b in model.Beatmaps) @@ -322,7 +322,7 @@ namespace osu.Game.Beatmaps /// /// Create all required s for the provided archive. /// - private List createBeatmapDifficulties(ArchiveReader reader) + private List createBeatmapDifficulties(BeatmapSetInfo model, ArchiveReader reader) { var beatmapInfos = new List(); @@ -342,6 +342,14 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); + // ensure we have the same online set ID as the set itself. + beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID; + beatmap.BeatmapInfo.Metadata.OnlineBeatmapSetID = model.OnlineBeatmapSetID; + + // check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. + if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) + beatmap.BeatmapInfo.OnlineBeatmapID = null; + RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); beatmap.BeatmapInfo.Ruleset = ruleset; From 749a69567b7bf5a26123b361b0be743f38d7ebe3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 16:18:20 +0900 Subject: [PATCH 38/70] Add EF tooling references --- osu.Desktop/osu.Desktop.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 3a35568f8f..af027da2fc 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -20,6 +20,8 @@ osu.Desktop.Program + + @@ -36,4 +38,8 @@ + + + + \ No newline at end of file From 6f72e5a876762bb5d10b28b4d8da24ae5b5ddb71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 29 May 2018 10:27:21 +0200 Subject: [PATCH 39/70] Fix Debug mode instead of Release mode for mono debug target --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 11141dc182..32c82685c0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,7 @@ }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe", + "program": "${workspaceRoot}/osu.Game.Tests/bin/Release/net471/osu.Game.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release, msbuild)", "runtimeExecutable": null, From 4a18951cce0279731bf7afae07f330dda4d2d37f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 18:37:45 +0900 Subject: [PATCH 40/70] Report full error to log file --- osu.Game/Database/ArchiveModelManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 99f1e9f581..6a31182370 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -206,8 +206,9 @@ namespace osu.Game.Database } } } - catch + catch (Exception e) { + Logger.Error(e, $"Import of {archive.Name} failed and has been rolled back.", LoggingTarget.Database); item = null; } From c18a5b5ac8d089c88146d3b723e10def14e27a38 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 19:31:26 +0900 Subject: [PATCH 41/70] Fix importing long filenames from stable --- osu.Desktop/OsuGameDesktop.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index a495d7048d..844db4a80f 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -12,6 +12,7 @@ using osu.Framework.Platform; using osu.Game; using OpenTK.Input; using Microsoft.Win32; +using osu.Framework.Platform.Windows; namespace osu.Desktop { @@ -40,7 +41,7 @@ namespace osu.Desktop /// /// A method of accessing an osu-stable install in a controlled fashion. /// - private class StableStorage : DesktopStorage + private class StableStorage : WindowsStorage { protected override string LocateBasePath() { From 31ab6f240841b5be96077c72e7761109e690c5e5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 May 2018 19:43:52 +0900 Subject: [PATCH 42/70] Fix event flushing sticking on early return --- osu.Game/Database/ArchiveModelManager.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 6a31182370..62d8c16946 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -174,7 +174,7 @@ namespace osu.Game.Database /// The archive to be imported. public TModel Import(ArchiveReader archive) { - TModel item; + TModel item = null; delayEvents(); try @@ -211,9 +211,12 @@ namespace osu.Game.Database Logger.Error(e, $"Import of {archive.Name} failed and has been rolled back.", LoggingTarget.Database); item = null; } + finally + { + // we only want to flush events after we've confirmed the write context didn't have any errors. + flushEvents(item != null); + } - // we only want to flush events after we've confirmed the write context didn't have any errors. - flushEvents(item != null); return item; } From e23e2bd3485045eb079b4c69f71b5cdf50b98260 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 13:37:52 +0900 Subject: [PATCH 43/70] Fix recycling never being performed due to incorrect ordering --- osu.Game/Database/DatabaseContextFactory.cs | 33 +++++++++++---------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index ec408456e3..f57246453e 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -64,24 +64,25 @@ namespace osu.Game.Database currentWriteDidWrite |= usage.PerformedWrite; currentWriteDidError |= usage.Errors.Any(); - if (usages > 0) return; - - if (currentWriteDidError) - currentWriteTransaction?.Rollback(); - else - currentWriteTransaction?.Commit(); - - currentWriteTransaction = null; - currentWriteDidWrite = false; - currentWriteDidError = false; - - if (currentWriteDidWrite) + if (usages == 0) { - // explicitly dispose to ensure any outstanding flushes happen as soon as possible (and underlying resources are purged). - usage.Context.Dispose(); + if (currentWriteDidError) + currentWriteTransaction?.Rollback(); + else + currentWriteTransaction?.Commit(); - // once all writes are complete, we want to refresh thread-specific contexts to make sure they don't have stale local caches. - recycleThreadContexts(); + if (currentWriteDidWrite || currentWriteDidError) + { + // explicitly dispose to ensure any outstanding flushes happen as soon as possible (and underlying resources are purged). + usage.Context.Dispose(); + + // once all writes are complete, we want to refresh thread-specific contexts to make sure they don't have stale local caches. + recycleThreadContexts(); + } + + currentWriteTransaction = null; + currentWriteDidWrite = false; + currentWriteDidError = false; } } finally From 4a7de043e080aeb087de9d67eb7b3627a3471bf7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 13:43:25 +0900 Subject: [PATCH 44/70] Recycle all contexts on beginning a write operation for the time being --- osu.Game/Database/DatabaseContextFactory.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index f57246453e..a1d371f431 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -48,7 +48,14 @@ namespace osu.Game.Database Monitor.Enter(writeLock); if (currentWriteTransaction == null && withTransaction) + { + // this mitigates the fact that changes on tracked entities will not be rolled back with the transaction by ensuring write operations are always executed in isolated contexts. + // if this results in sub-optimal efficiency, we may need to look into removing Database-level transactions in favour of running SaveChanges where we currently commit the transaction. + if (threadContexts.IsValueCreated) + recycleThreadContexts(); + currentWriteTransaction = threadContexts.Value.Database.BeginTransaction(); + } Interlocked.Increment(ref currentWriteUsages); From eb893174947ae5cf8d050d932b27658cfab990cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 13:43:43 +0900 Subject: [PATCH 45/70] Remove performance optimisation tracking disables to keep things simple for now --- osu.Game/Database/ArchiveModelManager.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 62d8c16946..1505ac0549 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -240,12 +240,8 @@ namespace osu.Game.Database /// The item to delete. public void Delete(TModel item) { - using (var usage = ContextFactory.GetForWrite()) + using (ContextFactory.GetForWrite()) { - var context = usage.Context; - - context.ChangeTracker.AutoDetectChangesEnabled = false; - // re-fetch the model on the import context. var foundModel = queryModel().Include(s => s.Files).ThenInclude(f => f.FileInfo).First(s => s.ID == item.ID); @@ -253,8 +249,6 @@ namespace osu.Game.Database if (ModelStore.Delete(foundModel)) Files.Dereference(foundModel.Files.Select(f => f.FileInfo).ToArray()); - - context.ChangeTracker.AutoDetectChangesEnabled = true; } } From 54e53f71909258c67383cf02d6ab5674f84f5609 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 15:44:35 +0900 Subject: [PATCH 46/70] Fix player getting loaded when exiting song select --- .../Screens/Select/Carousel/DrawableCarouselBeatmap.cs | 2 +- osu.Game/Screens/Select/EditSongSelect.cs | 2 +- osu.Game/Screens/Select/MatchSongSelect.cs | 2 +- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 10 ++++++---- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index f39952dc31..c5996327b9 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select.Carousel if (songSelect != null) { - startRequested = songSelect.FinaliseSelection; + startRequested = b => songSelect.FinaliseSelection(b); editRequested = songSelect.Edit; } diff --git a/osu.Game/Screens/Select/EditSongSelect.cs b/osu.Game/Screens/Select/EditSongSelect.cs index bca009e2c1..e1d71fdd05 100644 --- a/osu.Game/Screens/Select/EditSongSelect.cs +++ b/osu.Game/Screens/Select/EditSongSelect.cs @@ -7,7 +7,7 @@ namespace osu.Game.Screens.Select { protected override bool ShowFooter => false; - protected override bool OnSelectionFinalised() + protected override bool OnStart() { Exit(); return true; diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 3ffac591f3..a0c96d0cee 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -5,7 +5,7 @@ namespace osu.Game.Screens.Select { public class MatchSongSelect : SongSelect { - protected override bool OnSelectionFinalised() + protected override bool OnStart() { Schedule(() => { diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 7992930c45..8ce40fcfa0 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -137,7 +137,7 @@ namespace osu.Game.Screens.Select return false; } - protected override bool OnSelectionFinalised() + protected override bool OnStart() { if (player != null) return false; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4ffa9e2a90..cc725e7f05 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -227,7 +227,8 @@ namespace osu.Game.Screens.Select /// Call to make a selection and perform the default action for this SongSelect. /// /// An optional beatmap to override the current carousel selection. - public void FinaliseSelection(BeatmapInfo beatmap = null) + /// Whether to trigger . + public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true) { // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). @@ -243,14 +244,15 @@ namespace osu.Game.Screens.Select selectionChangedDebounce = null; } - OnSelectionFinalised(); + if (performStartAction) + OnStart(); } /// /// Called when a selection is made. /// /// If a resultant action occurred that takes the user away from SongSelect. - protected abstract bool OnSelectionFinalised(); + protected abstract bool OnStart(); private ScheduledDelegate selectionChangedDebounce; @@ -395,7 +397,7 @@ namespace osu.Game.Screens.Select protected override bool OnExiting(Screen next) { - FinaliseSelection(); + FinaliseSelection(performStartAction: false); beatmapInfoWedge.State = Visibility.Hidden; From 5872b61988d2386dfce5e488d882395ebdf36563 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 15:47:31 +0900 Subject: [PATCH 47/70] Fix potential double-disposal of player if PlayerLoader is finalised --- osu.Game/Screens/Play/PlayerLoader.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 9c8961498a..2d5bc889c3 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -209,8 +209,11 @@ namespace osu.Game.Screens.Play { base.Dispose(isDisposing); - // if the player never got pushed, we should explicitly dispose it. - loadTask?.ContinueWith(_ => player.Dispose()); + if (isDisposing) + { + // if the player never got pushed, we should explicitly dispose it. + loadTask?.ContinueWith(_ => player.Dispose()); + } } private class BeatmapMetadataDisplay : Container From a28e71995d818c500c043fc5b83253d5ae57520f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 16:15:00 +0900 Subject: [PATCH 48/70] Offload database query to task Allows song select to load a touch faster, in theory. --- osu.Game/Beatmaps/BeatmapManager.cs | 8 +++++++- osu.Game/Screens/Select/SongSelect.cs | 9 +-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 36fde8a319..83f3fe7a35 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -241,7 +241,13 @@ namespace osu.Game.Beatmaps /// Returns a list of all usable s. /// /// A list of available . - public List GetAllUsableBeatmapSets() => beatmaps.ConsumableItems.Where(s => !s.DeletePending && !s.Protected).ToList(); + public List GetAllUsableBeatmapSets() => GetAllUsableBeatmapSetsEnumerable().ToList(); + + /// + /// Returns a list of all usable s. + /// + /// A list of available . + public IQueryable GetAllUsableBeatmapSetsEnumerable() => beatmaps.ConsumableItems.Where(s => !s.DeletePending && !s.Protected); /// /// Perform a lookup query on available s. diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4ffa9e2a90..41aba9a126 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Threading; using OpenTK; using OpenTK.Input; using osu.Framework.Allocation; @@ -63,8 +62,6 @@ namespace osu.Game.Screens.Select private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeBeatmap; - private CancellationTokenSource initialAddSetsTask; - private DependencyContainer dependencies; protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent); @@ -207,9 +204,7 @@ namespace osu.Game.Screens.Select sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty"); sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand"); - initialAddSetsTask = new CancellationTokenSource(); - - Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSets(); + Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSetsEnumerable(); Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.TriggerChange(); @@ -417,8 +412,6 @@ namespace osu.Game.Screens.Select beatmaps.BeatmapHidden -= onBeatmapHidden; beatmaps.BeatmapRestored -= onBeatmapRestored; } - - initialAddSetsTask?.Cancel(); } /// From 6d6b186fb2625988f911ad01db16df6c11e175bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 19:25:39 +0900 Subject: [PATCH 49/70] Fix delayed logo animations playing even if screen has already been exited --- osu.Game/Screens/OsuScreen.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index cd9cbe119f..db9807b9ab 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -231,7 +231,10 @@ namespace osu.Game.Screens private void applyArrivingDefaults(bool isResuming) { - logo.AppendAnimatingAction(() => LogoArriving(logo, isResuming), true); + logo.AppendAnimatingAction(() => + { + if (IsCurrentScreen) LogoArriving(logo, isResuming); + }, true); if (backgroundParallaxContainer != null) backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount; From 0dafcf00b7038d41b1ef33e0aa87c76d115b4763 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 19:50:00 +0900 Subject: [PATCH 50/70] Fix some discrepancies with the main menu logo transitions --- osu.Game/Screens/Menu/ButtonSystem.cs | 51 +++++++++++++++------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 8b88204ed0..8282e7e2fe 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -325,52 +325,57 @@ namespace osu.Game.Screens.Menu { if (logo == null) return; - logoDelayedAction?.Cancel(); - switch (state) { case MenuState.Exit: case MenuState.Initial: - logoTracking = false; - + logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => - { - hideOverlaysOnEnter.Value = true; - allowOpeningOverlays.Value = false; + { + logoTracking = false; - logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.Both; + hideOverlaysOnEnter.Value = true; + allowOpeningOverlays.Value = false; - logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); - logo.ScaleTo(1, 800, Easing.OutExpo); - }, 150); + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; + logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); + logo.ScaleTo(1, 800, Easing.OutExpo); + }, buttonArea.Alpha * 150); break; case MenuState.TopLevel: case MenuState.Play: - logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.None; - switch (lastState) { case MenuState.TopLevel: // coming from toplevel to play + break; case MenuState.Initial: - logoTracking = false; - logo.ScaleTo(0.5f, 200, Easing.In); + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.None; + + bool impact = logo.Scale.X > 0.6f; + + if (lastState == MenuState.Initial) + logo.ScaleTo(0.5f, 200, Easing.In); logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In); + logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => - { - logoTracking = true; + { + logoTracking = true; - logo.Impact(); + if (impact) + logo.Impact(); - hideOverlaysOnEnter.Value = false; - allowOpeningOverlays.Value = true; - }, 200); + hideOverlaysOnEnter.Value = false; + allowOpeningOverlays.Value = true; + }, (1 - buttonArea.Alpha) * 200); break; default: + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.None; logoTracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; From 0caf15166e3bfc06ca34725664a816393c1e11ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 May 2018 20:05:31 +0900 Subject: [PATCH 51/70] Remove unnecessary FinishTransforms --- osu.Game/Screens/Menu/ButtonSystem.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 8282e7e2fe..983ba70fa5 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -254,9 +254,6 @@ namespace osu.Game.Screens.Menu backButton.ContractStyle = 0; settingsButton.ContractStyle = 0; - if (state == MenuState.TopLevel) - buttonArea.FinishTransforms(true); - updateLogoState(lastState); using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true)) From ff93a54a64de5f81039f31f4faa7f08f2d0b432c Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Wed, 30 May 2018 23:16:54 -0300 Subject: [PATCH 52/70] Default Type to Title, use ToLower for the screen type title. --- osu.Game/Screens/Multi/Header.cs | 2 +- osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs | 1 - osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Multi/Header.cs b/osu.Game/Screens/Multi/Header.cs index fb4da45aca..46610a36d8 100644 --- a/osu.Game/Screens/Multi/Header.cs +++ b/osu.Game/Screens/Multi/Header.cs @@ -86,7 +86,7 @@ namespace osu.Game.Screens.Multi }, }; - breadcrumbs.Current.ValueChanged += s => screenType.Text = ((MultiplayerScreen)s).Type; + breadcrumbs.Current.ValueChanged += s => screenType.Text = ((MultiplayerScreen)s).Type.ToLower(); breadcrumbs.Current.TriggerChange(); } diff --git a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs index f0c93b1146..016babcaa5 100644 --- a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs +++ b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs @@ -25,7 +25,6 @@ namespace osu.Game.Screens.Multi.Screens.Lounge protected readonly FillFlowContainer RoomsContainer; protected readonly RoomInspector Inspector; - public override string Type => "lounge"; public override string Title => "Lounge"; protected override Container TransitionContent => content; diff --git a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs index cdfa17a7a6..fa9b40684c 100644 --- a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs +++ b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Multi.Screens /// /// The type to display in the title of the . /// - public abstract string Type { get; } + public virtual string Type => Title; protected override void OnEntering(Screen last) { From 319faf12f7a9b4e010b318a8f470db825dadbd04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 May 2018 12:39:56 +0900 Subject: [PATCH 53/70] Fix incorrect naming of label --- osu.Game.Tests/Visual/TestCaseMods.cs | 8 ++++---- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index cf26230868..3255478bea 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -199,13 +199,13 @@ namespace osu.Game.Tests.Visual private void testRankedText(Mod mod) { AddWaitStep(1, "wait for fade"); - AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha == 0); + AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); selectNext(mod); AddWaitStep(1, "wait for fade"); - AddAssert("check for unranked", () => modSelect.RankedLabel.Alpha != 0); + AddAssert("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0); selectPrevious(mod); AddWaitStep(1, "wait for fade"); - AddAssert("check for ranked", () => modSelect.RankedLabel.Alpha == 0); + AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); } private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1)); @@ -241,7 +241,7 @@ namespace osu.Game.Tests.Visual } public new OsuSpriteText MultiplierLabel => base.MultiplierLabel; - public new OsuSpriteText RankedLabel => base.RankedLabel; + public new OsuSpriteText UnrankedLabel => base.UnrankedLabel; public new TriangleButton DeselectAllButton => base.DeselectAllButton; public new Color4 LowMultiplierColour => base.LowMultiplierColour; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 69f409c3d2..3c44532627 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Mods protected Color4 LowMultiplierColour, HighMultiplierColour; protected readonly TriangleButton DeselectAllButton; - protected readonly OsuSpriteText MultiplierLabel, RankedLabel; + protected readonly OsuSpriteText MultiplierLabel, UnrankedLabel; private readonly FillFlowContainer footerContainer; protected override bool BlockPassThroughKeyboard => false; @@ -107,9 +107,9 @@ namespace osu.Game.Overlays.Mods MultiplierLabel.FadeColour(Color4.White, 200); if (ranked) - RankedLabel.FadeOut(200); + UnrankedLabel.FadeOut(200); else - RankedLabel.FadeIn(200); + UnrankedLabel.FadeIn(200); } protected override void PopOut() @@ -373,7 +373,7 @@ namespace osu.Game.Overlays.Mods Top = 5 } }, - RankedLabel = new OsuSpriteText + UnrankedLabel = new OsuSpriteText { Font = @"Exo2.0-Bold", Text = @"(Unranked)", From 205aa1a3cdd5adf2927e78dcd9187306bf4f8889 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 May 2018 12:44:11 +0900 Subject: [PATCH 54/70] Fetch colour from OsuColour palette --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 3c44532627..5eb507c67c 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -58,6 +58,7 @@ namespace osu.Game.Overlays.Mods LowMultiplierColour = colours.Red; HighMultiplierColour = colours.Green; + UnrankedLabel.Colour = colours.Blue; if (osu != null) Ruleset.BindTo(osu.Ruleset); @@ -378,7 +379,6 @@ namespace osu.Game.Overlays.Mods Font = @"Exo2.0-Bold", Text = @"(Unranked)", TextSize = 30, - Colour = OsuColour.FromHex(@"66ccff"), Shadow = true, Margin = new MarginPadding { From 0f6c623ebb15b222cb21076a8d9d98a85d2ae3a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 May 2018 12:44:59 +0900 Subject: [PATCH 55/70] Tidy up some unnecessary lines --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 5eb507c67c..f1624721da 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -107,10 +107,7 @@ namespace osu.Game.Overlays.Mods else MultiplierLabel.FadeColour(Color4.White, 200); - if (ranked) - UnrankedLabel.FadeOut(200); - else - UnrankedLabel.FadeIn(200); + UnrankedLabel.FadeTo(ranked ? 0 : 1, 200); } protected override void PopOut() @@ -357,7 +354,6 @@ namespace osu.Game.Overlays.Mods { Text = @"Score Multiplier:", TextSize = 30, - Shadow = true, Margin = new MarginPadding { Top = 5, @@ -368,7 +364,6 @@ namespace osu.Game.Overlays.Mods { Font = @"Exo2.0-Bold", TextSize = 30, - Shadow = true, Margin = new MarginPadding { Top = 5 @@ -379,7 +374,6 @@ namespace osu.Game.Overlays.Mods Font = @"Exo2.0-Bold", Text = @"(Unranked)", TextSize = 30, - Shadow = true, Margin = new MarginPadding { Top = 5, From b7511251d99ee6158e918725a35a26134c5e3529 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 May 2018 12:50:01 +0900 Subject: [PATCH 56/70] Remove pointless FillMode specification --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 59d5ecd07f..d8c7b5130d 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -407,7 +407,6 @@ namespace osu.Game.Rulesets.Catch.UI public CatcherSprite() { Size = new Vector2(CATCHER_SIZE); - FillMode = FillMode.Fill; // Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling. OriginPosition = new Vector2(-0.02f, 0.06f) * CATCHER_SIZE; From e48b17fb0debb6d4a28c81d64ced8be3ef217c88 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 31 May 2018 15:17:59 +0900 Subject: [PATCH 57/70] Unindent --- osu.Game/Screens/Menu/ButtonSystem.cs | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 983ba70fa5..f212bfabf3 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -328,18 +328,18 @@ namespace osu.Game.Screens.Menu case MenuState.Initial: logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => - { - logoTracking = false; + { + logoTracking = false; - hideOverlaysOnEnter.Value = true; - allowOpeningOverlays.Value = false; + hideOverlaysOnEnter.Value = true; + allowOpeningOverlays.Value = false; - logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.Both; + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; - logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); - logo.ScaleTo(1, 800, Easing.OutExpo); - }, buttonArea.Alpha * 150); + logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); + logo.ScaleTo(1, 800, Easing.OutExpo); + }, buttonArea.Alpha * 150); break; case MenuState.TopLevel: case MenuState.Play: @@ -360,15 +360,15 @@ namespace osu.Game.Screens.Menu logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => - { - logoTracking = true; + { + logoTracking = true; - if (impact) - logo.Impact(); + if (impact) + logo.Impact(); - hideOverlaysOnEnter.Value = false; - allowOpeningOverlays.Value = true; - }, (1 - buttonArea.Alpha) * 200); + hideOverlaysOnEnter.Value = false; + allowOpeningOverlays.Value = true; + }, 200); break; default: logo.ClearTransforms(targetMember: nameof(Position)); From 6781b81336ba61b053d91028ba9a7ec1d06108c6 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Thu, 31 May 2018 05:48:42 -0300 Subject: [PATCH 58/70] Cleanup. --- osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs | 1 + osu.Game/Overlays/BeatmapSet/Header.cs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs index e25f5a9431..1976db907c 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs @@ -59,6 +59,7 @@ namespace osu.Game.Beatmaps.Drawables { displayedCover?.FadeOut(400); displayedCover?.Expire(); + displayedCover = null; if (beatmapSet != null) { diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 033f0b22d0..89c141ef17 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -61,8 +61,8 @@ namespace osu.Game.Overlays.BeatmapSet title.Text = BeatmapSet?.Metadata.Title ?? string.Empty; artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty; onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None; + cover.BeatmapSet = BeatmapSet; - cover.BeatmapSet = null; if (BeatmapSet != null) { downloadButtonsContainer.FadeIn(transition_duration); @@ -70,8 +70,6 @@ namespace osu.Game.Overlays.BeatmapSet noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration); videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); - - cover.BeatmapSet = BeatmapSet; } else { From 1095669a5583a6ca81e8e27e65fdc8d45655a704 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 31 May 2018 08:09:19 -0700 Subject: [PATCH 59/70] Match panel with web --- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 5 +++ .../API/Requests/APIResponseBeatmapSet.cs | 4 +++ osu.Game/Overlays/Direct/DirectGridPanel.cs | 33 +++++++++++++++---- osu.Game/Overlays/Direct/PlayButton.cs | 2 +- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index a70caf0207..8f985306e3 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -36,6 +36,11 @@ namespace osu.Game.Beatmaps /// public bool HasVideo { get; set; } + /// + /// Whether or not this beatmap set has a storyboard. + /// + public bool HasStoryboard { get; set; } + /// /// The different sizes of cover art for this beatmap set. /// diff --git a/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs b/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs index 2661303652..44c1216959 100644 --- a/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs @@ -30,6 +30,9 @@ namespace osu.Game.Online.API.Requests [JsonProperty(@"video")] private bool hasVideo { get; set; } + [JsonProperty(@"storyboard")] + private bool hasStoryboard { get; set; } + [JsonProperty(@"status")] private BeatmapSetOnlineStatus status { get; set; } @@ -65,6 +68,7 @@ namespace osu.Game.Online.API.Requests BPM = bpm, Status = status, HasVideo = hasVideo, + HasStoryboard = hasStoryboard, Submitted = submitted, Ranked = ranked, LastUpdated = lastUpdated, diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 9715615d14..1f0c097811 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -149,7 +149,7 @@ namespace osu.Game.Overlays.Direct { new OsuSpriteText { - Text = $"from {SetInfo.Metadata.Source}", + Text = $"{SetInfo.Metadata.Source}", TextSize = 14, Shadow = false, Colour = colours.Gray5, @@ -195,18 +195,18 @@ namespace osu.Game.Overlays.Direct new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0), }, }, - playButton = new PlayButton(SetInfo) - { - Margin = new MarginPadding { Top = 5, Left = 10 }, - Size = new Vector2(30), - Alpha = 0, - }, statusContainer = new FillFlowContainer { AutoSizeAxes = Axes.Both, Margin = new MarginPadding { Top = 5, Left = 5 }, Spacing = new Vector2(5), }, + playButton = new PlayButton(SetInfo) + { + Margin = new MarginPadding { Top = 5, Left = 10 }, + Size = new Vector2(30), + Alpha = 0, + }, }); if (SetInfo.OnlineInfo?.HasVideo ?? false) @@ -214,6 +214,11 @@ namespace osu.Game.Overlays.Direct statusContainer.Add(new IconPill(FontAwesome.fa_film)); } + if (SetInfo.OnlineInfo?.HasStoryboard ?? false) + { + statusContainer.Add(new IconPill(FontAwesome.fa_image)); + } + statusContainer.Add(new BeatmapSetOnlineStatusPill(12, new MarginPadding { Horizontal = 10, Vertical = 5 }) { Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None, @@ -233,5 +238,19 @@ namespace osu.Game.Overlays.Direct statusContainer.FadeIn(120, Easing.InOutQuint); } + + protected override void Update() + { + base.Update(); + + if (PreviewPlaying) + { + statusContainer.Hide(); + } + else if (!IsHovered) + { + statusContainer.Show(); + } + } } } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 4913b11ae1..131083c6ff 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Direct return; } - icon.Icon = playing ? FontAwesome.fa_pause : FontAwesome.fa_play; + icon.Icon = playing ? FontAwesome.fa_stop : FontAwesome.fa_play; icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); if (playing) From 729f2ec7251cc981b009412858d294adfc4477f3 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 31 May 2018 14:34:47 -0700 Subject: [PATCH 60/70] Match authorinfo with web --- osu.Game/Overlays/BeatmapSet/AuthorInfo.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs index 66e3148065..398518ef2b 100644 --- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs +++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs @@ -49,8 +49,8 @@ namespace osu.Game.Overlays.BeatmapSet fields.Children = new Drawable[] { - new Field("made by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"), - new Field("submitted on", online.Submitted.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold") + new Field("mapped by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"), + new Field("submitted on", online.Submitted.ToString(@"MMMM d, yyyy"), @"Exo2.0-Bold") { Margin = new MarginPadding { Top = 5 }, }, @@ -58,11 +58,11 @@ namespace osu.Game.Overlays.BeatmapSet if (online.Ranked.HasValue) { - fields.Add(new Field("ranked on ", online.Ranked.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")); + fields.Add(new Field("ranked on", online.Ranked.Value.ToString(@"MMMM d, yyyy"), @"Exo2.0-Bold")); } else if (online.LastUpdated.HasValue) { - fields.Add(new Field("last updated on ", online.LastUpdated.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")); + fields.Add(new Field("last updated on", online.LastUpdated.Value.ToString(@"MMMM d, yyyy"), @"Exo2.0-Bold")); } } From b9c601074d6659150b237d0f7c712d30d50ee3b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Jun 2018 15:45:09 +0900 Subject: [PATCH 61/70] Formatting fixes --- .../Screens/Multi/Components/BeatmapTitle.cs | 18 ++++-------------- .../Multi/Components/ParticipantCount.cs | 4 ++-- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs index daa362409a..42863754c5 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs @@ -22,6 +22,7 @@ namespace osu.Game.Screens.Multi.Components } private BeatmapInfo beatmap; + public BeatmapInfo Beatmap { set @@ -41,18 +42,9 @@ namespace osu.Game.Screens.Multi.Components Children = new[] { - beatmapTitle = new OsuSpriteText - { - Font = @"Exo2.0-BoldItalic", - }, - beatmapDash = new OsuSpriteText - { - Font = @"Exo2.0-BoldItalic", - }, - beatmapArtist = new OsuSpriteText - { - Font = @"Exo2.0-RegularItalic", - }, + beatmapTitle = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", }, + beatmapDash = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", }, + beatmapArtist = new OsuSpriteText { Font = @"Exo2.0-RegularItalic", }, }; } @@ -65,7 +57,6 @@ namespace osu.Game.Screens.Multi.Components protected override void LoadComplete() { base.LoadComplete(); - updateText(); } @@ -74,7 +65,6 @@ namespace osu.Game.Screens.Multi.Components if (beatmap == null) { beatmapTitle.Current = beatmapArtist.Current = null; - beatmapTitle.Text = "Changing map"; beatmapDash.Text = beatmapArtist.Text = string.Empty; } diff --git a/osu.Game/Screens/Multi/Components/ParticipantCount.cs b/osu.Game/Screens/Multi/Components/ParticipantCount.cs index 96e2bd7bee..e47a529ff8 100644 --- a/osu.Game/Screens/Multi/Components/ParticipantCount.cs +++ b/osu.Game/Screens/Multi/Components/ParticipantCount.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Multi.Components public int Count { - set { count.Text = value.ToString(); } + set => count.Text = value.ToString(); } public int? Max @@ -31,8 +31,8 @@ namespace osu.Game.Screens.Multi.Components else { slash.FadeIn(transition_duration); - max.FadeIn(transition_duration); max.Text = value.ToString(); + max.FadeIn(transition_duration); } } } From 8dd36ee1a98a54ccf4ede99a4f829b1fc6b2ed19 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 06:08:57 -0300 Subject: [PATCH 62/70] Default Max to null in ParticipantCount. --- osu.Game/Screens/Multi/Components/ParticipantCount.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Multi/Components/ParticipantCount.cs b/osu.Game/Screens/Multi/Components/ParticipantCount.cs index e47a529ff8..2e9183d047 100644 --- a/osu.Game/Screens/Multi/Components/ParticipantCount.cs +++ b/osu.Game/Screens/Multi/Components/ParticipantCount.cs @@ -62,6 +62,8 @@ namespace osu.Game.Screens.Multi.Components Font = @"Exo2.0-Light" }, }; + + Max = null; } } } From 59762c0393a01b14ba92467076dc19cd54fcef0a Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 06:15:23 -0300 Subject: [PATCH 63/70] Change Room.Participants to an IEnumerable. --- osu.Game/Online/Multiplayer/Room.cs | 3 ++- osu.Game/Screens/Multi/Components/DrawableRoom.cs | 2 +- osu.Game/Screens/Multi/Components/RoomInspector.cs | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index ae3fb5ec6e..b076afbcdb 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Framework.Configuration; using osu.Game.Beatmaps; using osu.Game.Users; @@ -16,6 +17,6 @@ namespace osu.Game.Online.Multiplayer public Bindable Type = new Bindable(); public Bindable Beatmap = new Bindable(); public Bindable MaxParticipants = new Bindable(); - public Bindable Participants = new Bindable(); + public Bindable> Participants = new Bindable>(); } } diff --git a/osu.Game/Screens/Multi/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs index d31019a259..54bd0ae7cc 100644 --- a/osu.Game/Screens/Multi/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Multi.Components private readonly Bindable statusBind = new Bindable(); private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); - private readonly Bindable participantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); public readonly Room Room; diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index 14f4feab05..22bca1efc7 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; @@ -33,7 +34,7 @@ namespace osu.Game.Screens.Multi.Components private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); private readonly Bindable maxParticipantsBind = new Bindable(); - private readonly Bindable participantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); private OsuColour colours; private Box statusStrip; @@ -214,7 +215,7 @@ namespace osu.Game.Screens.Multi.Components participantsBind.ValueChanged += p => { - participantCount.Count = p.Length; + participantCount.Count = p.Count(); participantInfo.Participants = p; participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u)); }; From 9b7741b353a6d71d88c836b51724ab26013de90f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Jun 2018 22:19:11 +0900 Subject: [PATCH 64/70] Avoid using update for fading logic --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 22 +++++---------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 1f0c097811..ed4630a8e7 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -223,34 +223,22 @@ namespace osu.Game.Overlays.Direct { Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None, }); + + PreviewPlaying.ValueChanged += _ => updateStatusContainer(); } protected override bool OnHover(InputState state) { - statusContainer.FadeOut(120, Easing.InOutQuint); - + updateStatusContainer(); return base.OnHover(state); } protected override void OnHoverLost(InputState state) { base.OnHoverLost(state); - - statusContainer.FadeIn(120, Easing.InOutQuint); + updateStatusContainer(); } - protected override void Update() - { - base.Update(); - - if (PreviewPlaying) - { - statusContainer.Hide(); - } - else if (!IsHovered) - { - statusContainer.Show(); - } - } + private void updateStatusContainer() => statusContainer.FadeTo(IsHovered || PreviewPlaying ? 0 : 1, 120, Easing.InOutQuint); } } From de64e4500ffcca65b31ccc36a77ff4fb31e553f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Jun 2018 22:20:28 +0900 Subject: [PATCH 65/70] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index aebfa5bc5c..804a4b81b8 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit aebfa5bc5c634c1fd0c103e0c17518e5111a67c7 +Subproject commit 804a4b81b89cb4569af5221e6fa2296d559c28fb From cc32adf51fb008e5e9573397c5c320cb8e3ea075 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 14:28:24 -0300 Subject: [PATCH 66/70] Move max text updating into updateMax. --- .../Multi/Components/ParticipantCount.cs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/ParticipantCount.cs b/osu.Game/Screens/Multi/Components/ParticipantCount.cs index 2e9183d047..e7183cbd92 100644 --- a/osu.Game/Screens/Multi/Components/ParticipantCount.cs +++ b/osu.Game/Screens/Multi/Components/ParticipantCount.cs @@ -12,28 +12,23 @@ namespace osu.Game.Screens.Multi.Components private const float text_size = 30; private const float transition_duration = 100; - private readonly OsuSpriteText count, slash, max; + private readonly OsuSpriteText count, slash, maxText; public int Count { set => count.Text = value.ToString(); } + private int? max; public int? Max { + get => max; set { - if (value == null) - { - slash.FadeOut(transition_duration); - max.FadeOut(transition_duration); - } - else - { - slash.FadeIn(transition_duration); - max.Text = value.ToString(); - max.FadeIn(transition_duration); - } + if (value == max) return; + max = value; + + updateMax(); } } @@ -56,14 +51,29 @@ namespace osu.Game.Screens.Multi.Components TextSize = text_size, Font = @"Exo2.0-Light" }, - max = new OsuSpriteText + maxText = new OsuSpriteText { TextSize = text_size, Font = @"Exo2.0-Light" }, }; - Max = null; + updateMax(); + } + + private void updateMax() + { + if (Max == null) + { + slash.FadeOut(transition_duration); + maxText.FadeOut(transition_duration); + } + else + { + slash.FadeIn(transition_duration); + maxText.Text = Max.ToString(); + maxText.FadeIn(transition_duration); + } } } } From 5d1421c0e9b97a8d1bdbd4e422fddb6a6777dfc1 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 1 Jun 2018 15:31:25 -0700 Subject: [PATCH 67/70] Fix visual settings expand button colour --- .../Play/PlayerSettings/PlayerSettingsGroup.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 0ffcdf94a6..cdde11c5f8 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -50,11 +50,11 @@ namespace osu.Game.Screens.Play.PlayerSettings content.ResizeHeightTo(0, transition_duration, Easing.OutQuint); } - button.FadeColour(expanded ? buttonActiveColour : Color4.White, 200, Easing.OutQuint); + button.FadeColour(expanded ? expandedColour : Color4.White, 200, Easing.OutQuint); } } - private Color4 buttonActiveColour; + private Color4 expandedColour; protected PlayerSettingsGroup() { @@ -130,7 +130,16 @@ namespace osu.Game.Screens.Play.PlayerSettings [BackgroundDependencyLoader] private void load(OsuColour colours) { - button.Colour = buttonActiveColour = colours.Yellow; + if (expanded) + { + button.Colour = colours.Yellow; + } + else + { + button.Colour = Color4.White; + } + + expandedColour = colours.Yellow; } protected override Container Content => content; From 8d3de3affbba360fe7d8d755d8a71c07899dcd79 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 1 Jun 2018 15:58:05 -0700 Subject: [PATCH 68/70] Use '?:' expression instead --- .../Screens/Play/PlayerSettings/PlayerSettingsGroup.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index cdde11c5f8..967cfd7fa0 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -130,14 +130,7 @@ namespace osu.Game.Screens.Play.PlayerSettings [BackgroundDependencyLoader] private void load(OsuColour colours) { - if (expanded) - { - button.Colour = colours.Yellow; - } - else - { - button.Colour = Color4.White; - } + button.FadeColour(expanded ? colours.Yellow : Color4.White); expandedColour = colours.Yellow; } From a0c643fae50982f78040a64c219fe5fdb44bfa47 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Sat, 2 Jun 2018 11:25:49 +0200 Subject: [PATCH 69/70] Fix SongProgressInfo timespan formatting --- osu.Game/Screens/Play/SongProgressInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SongProgressInfo.cs b/osu.Game/Screens/Play/SongProgressInfo.cs index b79c212ade..3156a646db 100644 --- a/osu.Game/Screens/Play/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/SongProgressInfo.cs @@ -92,6 +92,6 @@ namespace osu.Game.Screens.Play } } - private string formatTime(TimeSpan timeSpan) => $"{(timeSpan < TimeSpan.Zero ? "-" : "")}{timeSpan.Duration().TotalMinutes:N0}:{timeSpan.Duration().Seconds:D2}"; + private string formatTime(TimeSpan timeSpan) => $"{(timeSpan < TimeSpan.Zero ? "-" : "")}{Math.Floor(timeSpan.Duration().TotalMinutes)}:{timeSpan.Duration().Seconds:D2}"; } } From 0f13acf67e4af21539a04e7a265b1e0d0bacdbcf Mon Sep 17 00:00:00 2001 From: Joehu Date: Sat, 2 Jun 2018 12:52:31 -0700 Subject: [PATCH 70/70] Use updateExpanded method --- .../Screens/Play/PlayerSettings/PlayerSettingsGroup.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 967cfd7fa0..cff3eca895 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -50,7 +50,7 @@ namespace osu.Game.Screens.Play.PlayerSettings content.ResizeHeightTo(0, transition_duration, Easing.OutQuint); } - button.FadeColour(expanded ? expandedColour : Color4.White, 200, Easing.OutQuint); + updateExpanded(); } } @@ -130,11 +130,13 @@ namespace osu.Game.Screens.Play.PlayerSettings [BackgroundDependencyLoader] private void load(OsuColour colours) { - button.FadeColour(expanded ? colours.Yellow : Color4.White); - expandedColour = colours.Yellow; + + updateExpanded(); } + private void updateExpanded() => button.FadeColour(expanded ? expandedColour : Color4.White, 200, Easing.InOutQuint); + protected override Container Content => content; protected override bool OnHover(InputState state) => true;