From 281671a213f26a4d71bcc920205994b1f10c5db0 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 9 Oct 2019 21:04:26 +0300 Subject: [PATCH 01/86] Remove default combo colours usage from skins --- osu.Game/Skinning/LegacySkin.cs | 2 +- osu.Game/Skinning/LegacySkinDecoder.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index fea15458e4..3f0d4ca0d6 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -39,7 +39,7 @@ namespace osu.Game.Skinning using (LineBufferedReader reader = new LineBufferedReader(stream)) Configuration = new LegacySkinDecoder().Decode(reader); else - Configuration = new DefaultSkinConfiguration(); + Configuration = new SkinConfiguration(); if (storage != null) { diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index e97664e75e..ada2e075a7 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -5,14 +5,14 @@ using osu.Game.Beatmaps.Formats; namespace osu.Game.Skinning { - public class LegacySkinDecoder : LegacyDecoder + public class LegacySkinDecoder : LegacyDecoder { public LegacySkinDecoder() : base(1) { } - protected override void ParseLine(DefaultSkinConfiguration skin, Section section, string line) + protected override void ParseLine(SkinConfiguration skin, Section section, string line) { if (section != Section.Colours) { From 5e3f0f6c95f88845946bae4f96879628e42d9be7 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 9 Oct 2019 21:08:07 +0300 Subject: [PATCH 02/86] Return default combo colours if none provided --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 9 --------- osu.Game/Skinning/LegacyBeatmapSkin.cs | 3 +++ osu.Game/Skinning/LegacySkin.cs | 12 +++++++++++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 83d20da458..4899a53cf1 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -77,8 +77,6 @@ namespace osu.Game.Beatmaps.Formats return line; } - private bool hasComboColours; - private void handleColours(T output, string line) { var pair = SplitKeyVal(line); @@ -105,13 +103,6 @@ namespace osu.Game.Beatmaps.Formats { if (!(output is IHasComboColours tHasComboColours)) return; - if (!hasComboColours) - { - // remove default colours. - tHasComboColours.ComboColours.Clear(); - hasComboColours = true; - } - tHasComboColours.ComboColours.Add(colour); } else diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 6770da3c66..c9dec8a55e 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -9,6 +9,9 @@ namespace osu.Game.Skinning { public class LegacyBeatmapSkin : LegacySkin { + // Null should be returned in the case of no colours provided to fallback into current skin's colours. + protected override bool AllowDefaultColoursFallback => false; + public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, AudioManager audioManager) : base(createSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), audioManager, beatmap.Path) { diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 3f0d4ca0d6..bc12c00cd8 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -26,6 +26,11 @@ namespace osu.Game.Skinning [CanBeNull] protected IResourceStore Samples; + /// + /// Whether to allow default combo colours as fallback if none provided in this skin. + /// + protected virtual bool AllowDefaultColoursFallback => true; + public LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager) : this(skin, new LegacySkinResourceStore(skin, storage), audioManager, "skin.ini") { @@ -63,7 +68,12 @@ namespace osu.Game.Skinning switch (global) { case GlobalSkinConfiguration.ComboColours: - return SkinUtils.As(new Bindable>(Configuration.ComboColours)); + if (Configuration.ComboColours.Any()) + return SkinUtils.As(new Bindable>(Configuration.ComboColours)); + else if (AllowDefaultColoursFallback) + return SkinUtils.As(new Bindable>(new DefaultSkinConfiguration().ComboColours)); + + break; } break; From c2ada81c2313f77d5d7c19205da7dc92ee303e23 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 9 Oct 2019 21:08:54 +0300 Subject: [PATCH 03/86] Add tests ensuring correct behaviour --- .../Skins/TestSceneSkinConfigurationLookup.cs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index 578030748b..2ea66d8e41 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; @@ -21,8 +22,8 @@ namespace osu.Game.Tests.Skins [HeadlessTest] public class TestSceneSkinConfigurationLookup : OsuTestScene { - private LegacySkin source1; - private LegacySkin source2; + private SkinSource source1; + private SkinSource source2; private SkinRequester requester; [SetUp] @@ -116,6 +117,26 @@ namespace osu.Game.Tests.Skins }); } + [TestCase(false)] + [TestCase(true)] + public void TestEmptyComboColours(bool allowFallback) + { + AddStep("Add custom combo colours to fallback source", () => source1.Configuration.ComboColours = new List + { + new Color4(100, 150, 200, 255), + new Color4(55, 110, 166, 255), + new Color4(75, 125, 175, 255), + }); + AddStep("Clear combo colours from source", () => source2.Configuration.ComboColours.Clear()); + AddStep("Disable default fallback in source", () => source2.AllowColoursFallback = allowFallback); + + AddAssert($"Check retrieved combo colours from {(allowFallback ? "default skin" : "fallback source")}", () => + { + var expectedColours = allowFallback ? new DefaultSkinConfiguration().ComboColours : source1.Configuration.ComboColours; + return requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(expectedColours) ?? false; + }); + } + public enum LookupType { Test @@ -130,6 +151,9 @@ namespace osu.Game.Tests.Skins public class SkinSource : LegacySkin { + public bool AllowColoursFallback = true; + protected override bool AllowDefaultColoursFallback => AllowColoursFallback; + public SkinSource() : base(new SkinInfo(), null, null, string.Empty) { From 8d40c1b733d9b1800474c7b0d8dba4e36684080c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 9 Oct 2019 21:15:30 +0300 Subject: [PATCH 04/86] Remove default combo colours on empty skin test Checked differently in TestSceneSkinConfigurationLookup.TestEmptyComboColours() --- osu.Game.Tests/Resources/skin-empty.ini | 2 -- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 25 ++++++++----------- 2 files changed, 10 insertions(+), 17 deletions(-) delete mode 100644 osu.Game.Tests/Resources/skin-empty.ini diff --git a/osu.Game.Tests/Resources/skin-empty.ini b/osu.Game.Tests/Resources/skin-empty.ini deleted file mode 100644 index b6c319fe3c..0000000000 --- a/osu.Game.Tests/Resources/skin-empty.ini +++ /dev/null @@ -1,2 +0,0 @@ -[General] -Name: test skin \ No newline at end of file diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 0d96dd08da..76ce2331f5 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -13,28 +13,23 @@ namespace osu.Game.Tests.Skins [TestFixture] public class LegacySkinDecoderTest { - [TestCase(true)] - [TestCase(false)] - public void TestDecodeSkinColours(bool hasColours) + [Test] + public void TestDecodeSkinColours() { var decoder = new LegacySkinDecoder(); - using (var resStream = TestResources.OpenResource(hasColours ? "skin.ini" : "skin-empty.ini")) + using (var resStream = TestResources.OpenResource("skin.ini")) using (var stream = new LineBufferedReader(resStream)) { var comboColors = decoder.Decode(stream).ComboColours; - List expectedColors; - if (hasColours) - expectedColors = new List - { - new Color4(142, 199, 255, 255), - new Color4(255, 128, 128, 255), - new Color4(128, 255, 255, 255), - new Color4(100, 100, 100, 100), - }; - else - expectedColors = new DefaultSkin().Configuration.ComboColours; + List expectedColors = new List + { + new Color4(142, 199, 255, 255), + new Color4(255, 128, 128, 255), + new Color4(128, 255, 255, 255), + new Color4(100, 100, 100, 100), + }; Assert.AreEqual(expectedColors.Count, comboColors.Count); for (int i = 0; i < expectedColors.Count; i++) From cef6e2a26b49cdecd9663aa4af586292c8e8b4e6 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 6 Nov 2019 23:20:36 +0300 Subject: [PATCH 05/86] Move colours fallback logic to SkinConfiguration.ComboColours getter --- osu.Game/Skinning/DefaultSkinConfiguration.cs | 10 +------ osu.Game/Skinning/LegacySkin.cs | 9 ++++--- osu.Game/Skinning/SkinConfiguration.cs | 27 ++++++++++++++++++- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/osu.Game/Skinning/DefaultSkinConfiguration.cs b/osu.Game/Skinning/DefaultSkinConfiguration.cs index cd5975edac..8e89ab25b2 100644 --- a/osu.Game/Skinning/DefaultSkinConfiguration.cs +++ b/osu.Game/Skinning/DefaultSkinConfiguration.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osuTK.Graphics; - namespace osu.Game.Skinning { /// @@ -12,13 +10,7 @@ namespace osu.Game.Skinning { public DefaultSkinConfiguration() { - ComboColours.AddRange(new[] - { - new Color4(255, 192, 0, 255), - new Color4(0, 202, 0, 255), - new Color4(18, 124, 255, 255), - new Color4(242, 24, 57, 255), - }); + ComboColours = DefaultComboColours; } } } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index bc12c00cd8..ff1e501a06 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -46,6 +46,8 @@ namespace osu.Game.Skinning else Configuration = new SkinConfiguration(); + Configuration.AllowDefaultColoursFallback = AllowDefaultColoursFallback; + if (storage != null) { Samples = audioManager?.GetSampleStore(storage); @@ -68,10 +70,9 @@ namespace osu.Game.Skinning switch (global) { case GlobalSkinConfiguration.ComboColours: - if (Configuration.ComboColours.Any()) - return SkinUtils.As(new Bindable>(Configuration.ComboColours)); - else if (AllowDefaultColoursFallback) - return SkinUtils.As(new Bindable>(new DefaultSkinConfiguration().ComboColours)); + var comboColours = Configuration.ComboColours; + if (comboColours != null) + return SkinUtils.As(new Bindable>(comboColours)); break; } diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 54aac86e3c..57b969be33 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -14,7 +14,32 @@ namespace osu.Game.Skinning { public readonly SkinInfo SkinInfo = new SkinInfo(); - public List ComboColours { get; set; } = new List(); + internal bool AllowDefaultColoursFallback; + + public static List DefaultComboColours = new List + { + new Color4(255, 192, 0, 255), + new Color4(0, 202, 0, 255), + new Color4(18, 124, 255, 255), + new Color4(242, 24, 57, 255), + }; + + private List comboColours = new List(); + + public List ComboColours + { + get + { + if (comboColours.Count > 0) + return comboColours; + + if (AllowDefaultColoursFallback) + return DefaultComboColours; + + return null; + } + set => comboColours = value; + } public Dictionary CustomColours { get; set; } = new Dictionary(); From 61778232d8b76436458a87cd60a18d2443159d6d Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 6 Nov 2019 23:24:54 +0300 Subject: [PATCH 06/86] Rewrite inline comment --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index c9dec8a55e..4e020083a7 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -9,7 +9,7 @@ namespace osu.Game.Skinning { public class LegacyBeatmapSkin : LegacySkin { - // Null should be returned in the case of no colours provided to fallback into current skin's colours. + // Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer) protected override bool AllowDefaultColoursFallback => false; public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, AudioManager audioManager) From cea5bb396358c675b9d80327cb849d4c47b6aca2 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 7 Nov 2019 15:50:26 +0300 Subject: [PATCH 07/86] Return skin-empty.ini back --- osu.Game.Tests/Resources/skin-empty.ini | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 osu.Game.Tests/Resources/skin-empty.ini diff --git a/osu.Game.Tests/Resources/skin-empty.ini b/osu.Game.Tests/Resources/skin-empty.ini new file mode 100644 index 0000000000..b6c319fe3c --- /dev/null +++ b/osu.Game.Tests/Resources/skin-empty.ini @@ -0,0 +1,2 @@ +[General] +Name: test skin \ No newline at end of file From 41515e9e6cd87857af9a7b1ccbb71195f3691d86 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 7 Nov 2019 15:51:03 +0300 Subject: [PATCH 08/86] Update current tests to match the expected behaviour --- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 76ce2331f5..202161a1b8 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -13,23 +13,38 @@ namespace osu.Game.Tests.Skins [TestFixture] public class LegacySkinDecoderTest { - [Test] - public void TestDecodeSkinColours() + [TestCase(true)] + [TestCase(false)] + [TestCase(false, false)] + public void TestDecodeSkinColours(bool hasColours, bool canFallback = true) { var decoder = new LegacySkinDecoder(); - using (var resStream = TestResources.OpenResource("skin.ini")) + using (var resStream = TestResources.OpenResource(hasColours ? "skin.ini" : "skin-empty.ini")) using (var stream = new LineBufferedReader(resStream)) { - var comboColors = decoder.Decode(stream).ComboColours; + var skinConfiguration = decoder.Decode(stream); + skinConfiguration.AllowDefaultComboColoursFallback = canFallback; - List expectedColors = new List + var comboColors = skinConfiguration.ComboColours; + + if (!canFallback && !hasColours) + { + Assert.IsNull(comboColors); + return; + } + + List expectedColors; + if (hasColours) + expectedColors = new List { new Color4(142, 199, 255, 255), new Color4(255, 128, 128, 255), new Color4(128, 255, 255, 255), new Color4(100, 100, 100, 100), }; + else + expectedColors = SkinConfiguration.DefaultComboColours; Assert.AreEqual(expectedColors.Count, comboColors.Count); for (int i = 0; i < expectedColors.Count; i++) From 808543885f34f26b995a6446d6b7a910fe1b0ea8 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 7 Nov 2019 15:54:30 +0300 Subject: [PATCH 09/86] Change ComboColours type to IReadOnlyList Also exposes functions to modify the internal list (AddComboColours, ClearComboColours) --- .../Skins/TestSceneSkinConfigurationLookup.cs | 17 +++++++---------- osu.Game/Beatmaps/Formats/IHasComboColours.cs | 15 ++++++++++++++- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- .../Objects/Drawables/DrawableHitObject.cs | 2 +- osu.Game/Skinning/DefaultLegacySkin.cs | 7 +++---- osu.Game/Skinning/DefaultSkin.cs | 2 +- osu.Game/Skinning/LegacySkin.cs | 2 +- osu.Game/Skinning/SkinConfiguration.cs | 10 ++++++++-- 8 files changed, 36 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index 2ea66d8e41..c945568753 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Skins [Test] public void TestGlobalLookup() { - AddAssert("Check combo colours", () => requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.Count > 0); + AddAssert("Check combo colours", () => requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.Count > 0); } [Test] @@ -121,19 +121,19 @@ namespace osu.Game.Tests.Skins [TestCase(true)] public void TestEmptyComboColours(bool allowFallback) { - AddStep("Add custom combo colours to fallback source", () => source1.Configuration.ComboColours = new List + AddStep("Add custom combo colours to source1", () => source1.Configuration.ComboColours = new List { new Color4(100, 150, 200, 255), new Color4(55, 110, 166, 255), new Color4(75, 125, 175, 255), }); - AddStep("Clear combo colours from source", () => source2.Configuration.ComboColours.Clear()); - AddStep("Disable default fallback in source", () => source2.AllowColoursFallback = allowFallback); + AddStep("Clear combo colours from source2", () => source2.Configuration.ClearComboColours()); + AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = allowFallback); - AddAssert($"Check retrieved combo colours from {(allowFallback ? "default skin" : "fallback source")}", () => + AddAssert($"Check retrieved combo colours from {(allowFallback ? "source1" : "fallback source")}", () => { - var expectedColours = allowFallback ? new DefaultSkinConfiguration().ComboColours : source1.Configuration.ComboColours; - return requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(expectedColours) ?? false; + var expectedColours = allowFallback ? SkinConfiguration.DefaultComboColours : source1.Configuration.ComboColours; + return requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(expectedColours) ?? false; }); } @@ -151,9 +151,6 @@ namespace osu.Game.Tests.Skins public class SkinSource : LegacySkin { - public bool AllowColoursFallback = true; - protected override bool AllowDefaultColoursFallback => AllowColoursFallback; - public SkinSource() : base(new SkinInfo(), null, null, string.Empty) { diff --git a/osu.Game/Beatmaps/Formats/IHasComboColours.cs b/osu.Game/Beatmaps/Formats/IHasComboColours.cs index 4c15cb96d1..5ef31c1904 100644 --- a/osu.Game/Beatmaps/Formats/IHasComboColours.cs +++ b/osu.Game/Beatmaps/Formats/IHasComboColours.cs @@ -8,6 +8,19 @@ namespace osu.Game.Beatmaps.Formats { public interface IHasComboColours { - List ComboColours { get; set; } + /// + /// Retrieves the list of combo colours for presentation only. + /// + IReadOnlyList ComboColours { get; set; } + + /// + /// Adds combo colours to the list. + /// + void AddComboColours(params Color4[] colours); + + /// + /// Clear current combo colours from the list. + /// + void ClearComboColours(); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 4899a53cf1..ddaa04b657 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -103,7 +103,7 @@ namespace osu.Game.Beatmaps.Formats { if (!(output is IHasComboColours tHasComboColours)) return; - tHasComboColours.ComboColours.Add(colour); + tHasComboColours.AddComboColours(colour); } else { diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index f8bc74b2a6..09ff7bfded 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -265,7 +265,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { if (HitObject is IHasComboInformation combo) { - var comboColours = CurrentSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value; + var comboColours = CurrentSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value; AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; } } diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index 4b6eea6b6e..6eda0dfb34 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -13,13 +13,12 @@ namespace osu.Game.Skinning : base(Info, storage, audioManager, string.Empty) { Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); - Configuration.ComboColours.AddRange(new[] - { + Configuration.AddComboColours( new Color4(255, 192, 0, 255), new Color4(0, 202, 0, 255), new Color4(18, 124, 255, 255), - new Color4(242, 24, 57, 255), - }); + new Color4(242, 24, 57, 255) + ); } public static SkinInfo Info { get; } = new SkinInfo diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index 529c1afca5..2a065ea3d7 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -35,7 +35,7 @@ namespace osu.Game.Skinning switch (global) { case GlobalSkinConfiguration.ComboColours: - return SkinUtils.As(new Bindable>(Configuration.ComboColours)); + return SkinUtils.As(new Bindable>(Configuration.ComboColours)); } break; diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index ff1e501a06..94c2c8668f 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -72,7 +72,7 @@ namespace osu.Game.Skinning case GlobalSkinConfiguration.ComboColours: var comboColours = Configuration.ComboColours; if (comboColours != null) - return SkinUtils.As(new Bindable>(comboColours)); + return SkinUtils.As(new Bindable>(comboColours)); break; } diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 57b969be33..1fd781a5b3 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Beatmaps.Formats; using osuTK.Graphics; @@ -26,7 +28,7 @@ namespace osu.Game.Skinning private List comboColours = new List(); - public List ComboColours + public IReadOnlyList ComboColours { get { @@ -38,9 +40,13 @@ namespace osu.Game.Skinning return null; } - set => comboColours = value; + set => comboColours = value.ToList(); } + public void AddComboColours(params Color4[] colours) => colours.ForEach(c => comboColours.Add(c)); + + public void ClearComboColours() => comboColours.Clear(); + public Dictionary CustomColours { get; set; } = new Dictionary(); public readonly Dictionary ConfigDictionary = new Dictionary(); From 9874ce49ce6f81165862961ee6244b2267629c9a Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 7 Nov 2019 15:55:34 +0300 Subject: [PATCH 10/86] Move fallback allowance to the skin configuration only. --- osu.Game/Skinning/LegacyBeatmapSkin.cs | 5 ++--- osu.Game/Skinning/LegacySkin.cs | 7 ------- osu.Game/Skinning/SkinConfiguration.cs | 7 +++++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 4e020083a7..fa7e895a28 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -9,12 +9,11 @@ namespace osu.Game.Skinning { public class LegacyBeatmapSkin : LegacySkin { - // Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer) - protected override bool AllowDefaultColoursFallback => false; - public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, AudioManager audioManager) : base(createSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), audioManager, beatmap.Path) { + // Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer) + Configuration.AllowDefaultComboColoursFallback = false; } private static SkinInfo createSkinInfo(BeatmapInfo beatmap) => diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 94c2c8668f..359acc3a8f 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -26,11 +26,6 @@ namespace osu.Game.Skinning [CanBeNull] protected IResourceStore Samples; - /// - /// Whether to allow default combo colours as fallback if none provided in this skin. - /// - protected virtual bool AllowDefaultColoursFallback => true; - public LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager) : this(skin, new LegacySkinResourceStore(skin, storage), audioManager, "skin.ini") { @@ -46,8 +41,6 @@ namespace osu.Game.Skinning else Configuration = new SkinConfiguration(); - Configuration.AllowDefaultColoursFallback = AllowDefaultColoursFallback; - if (storage != null) { Samples = audioManager?.GetSampleStore(storage); diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 1fd781a5b3..da833acd98 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -16,7 +16,10 @@ namespace osu.Game.Skinning { public readonly SkinInfo SkinInfo = new SkinInfo(); - internal bool AllowDefaultColoursFallback; + /// + /// Whether to allow as a fallback list for when no combo colours are provided. + /// + internal bool AllowDefaultComboColoursFallback = true; public static List DefaultComboColours = new List { @@ -35,7 +38,7 @@ namespace osu.Game.Skinning if (comboColours.Count > 0) return comboColours; - if (AllowDefaultColoursFallback) + if (AllowDefaultComboColoursFallback) return DefaultComboColours; return null; From 164cb66f6aaa001204b2b2c9054d5e6c3fa47bf5 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 7 Nov 2019 16:13:10 +0300 Subject: [PATCH 11/86] Fix indention --- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 202161a1b8..e2f556dcc3 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -35,7 +35,9 @@ namespace osu.Game.Tests.Skins } List expectedColors; + if (hasColours) + { expectedColors = new List { new Color4(142, 199, 255, 255), @@ -43,8 +45,11 @@ namespace osu.Game.Tests.Skins new Color4(128, 255, 255, 255), new Color4(100, 100, 100, 100), }; + } else + { expectedColors = SkinConfiguration.DefaultComboColours; + } Assert.AreEqual(expectedColors.Count, comboColors.Count); for (int i = 0; i < expectedColors.Count; i++) From 8ed7bc3f5366ec7b8a98b47439616280d6bc4f25 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 7 Nov 2019 18:42:17 +0300 Subject: [PATCH 12/86] Fix another indention --- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index e2f556dcc3..003b3f5e56 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -39,12 +39,12 @@ namespace osu.Game.Tests.Skins if (hasColours) { expectedColors = new List - { - new Color4(142, 199, 255, 255), - new Color4(255, 128, 128, 255), - new Color4(128, 255, 255, 255), - new Color4(100, 100, 100, 100), - }; + { + new Color4(142, 199, 255, 255), + new Color4(255, 128, 128, 255), + new Color4(128, 255, 255, 255), + new Color4(100, 100, 100, 100), + }; } else { From 517f547590462f6fe26b6cdbe1b55814f5847141 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 7 Nov 2019 19:12:18 +0300 Subject: [PATCH 13/86] Fix failing test --- osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 6d7159a825..c6d1f9da29 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -130,7 +130,7 @@ namespace osu.Game.Tests.Gameplay switch (global) { case GlobalSkinConfiguration.ComboColours: - return SkinUtils.As(new Bindable>(ComboColours)); + return SkinUtils.As(new Bindable>(ComboColours)); } break; From 1e24ee795613543c1d32756a374a6ec2168a7540 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 24 Nov 2019 02:07:56 +0300 Subject: [PATCH 14/86] Remove ClearComboColours() --- osu.Game/Beatmaps/Formats/IHasComboColours.cs | 5 ----- osu.Game/Skinning/SkinConfiguration.cs | 2 -- 2 files changed, 7 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/IHasComboColours.cs b/osu.Game/Beatmaps/Formats/IHasComboColours.cs index 5ef31c1904..ac0d32dbaa 100644 --- a/osu.Game/Beatmaps/Formats/IHasComboColours.cs +++ b/osu.Game/Beatmaps/Formats/IHasComboColours.cs @@ -17,10 +17,5 @@ namespace osu.Game.Beatmaps.Formats /// Adds combo colours to the list. /// void AddComboColours(params Color4[] colours); - - /// - /// Clear current combo colours from the list. - /// - void ClearComboColours(); } } diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index da833acd98..94a1160b38 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -48,8 +48,6 @@ namespace osu.Game.Skinning public void AddComboColours(params Color4[] colours) => colours.ForEach(c => comboColours.Add(c)); - public void ClearComboColours() => comboColours.Clear(); - public Dictionary CustomColours { get; set; } = new Dictionary(); public readonly Dictionary ConfigDictionary = new Dictionary(); From 0f9978b34a8e250ba6458dd9ecee6eb90529a403 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 24 Nov 2019 02:08:36 +0300 Subject: [PATCH 15/86] Use AddRange instead --- osu.Game/Skinning/SkinConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 94a1160b38..0a21594f2a 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -46,7 +46,7 @@ namespace osu.Game.Skinning set => comboColours = value.ToList(); } - public void AddComboColours(params Color4[] colours) => colours.ForEach(c => comboColours.Add(c)); + public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours); public Dictionary CustomColours { get; set; } = new Dictionary(); From 5bf6e57eb0f19b4fedc09d06ca1e5d52cef5b129 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 24 Nov 2019 02:16:43 +0300 Subject: [PATCH 16/86] Remove unnecessary usage --- osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs | 1 - osu.Game/Skinning/SkinConfiguration.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index c945568753..c300799476 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -127,7 +127,6 @@ namespace osu.Game.Tests.Skins new Color4(55, 110, 166, 255), new Color4(75, 125, 175, 255), }); - AddStep("Clear combo colours from source2", () => source2.Configuration.ClearComboColours()); AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = allowFallback); AddAssert($"Check retrieved combo colours from {(allowFallback ? "source1" : "fallback source")}", () => diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 0a21594f2a..3bfc941fd7 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Beatmaps.Formats; using osuTK.Graphics; From b795532aa5db67c7c0e5242c3607dcede7b9fbc1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Dec 2019 19:43:16 +0800 Subject: [PATCH 17/86] add difficulty adjustment mods --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 6 +++ .../Mods/CatchModDifficultyAdjust.cs | 51 ++++++++++++++++++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 1 + .../Mods/ManiaModDifficultyAdjust.cs | 22 ++++++++ .../Mods/OsuModDifficultyAdjust.cs | 52 +++++++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + .../Mods/TaikoModDifficultyAdjust.cs | 42 +++++++++++++++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 6 +++ osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 43 +++++++++++++++ 9 files changed, 224 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs create mode 100644 osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs create mode 100644 osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs create mode 100644 osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 71d68ace94..6495c5379b 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -98,6 +98,12 @@ namespace osu.Game.Rulesets.Catch new CatchModFlashlight(), }; + case ModType.Conversion: + return new Mod[] + { + new CatchModDifficultyAdjust(), + }; + case ModType.Automation: return new Mod[] { diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs new file mode 100644 index 0000000000..7dfd5e8964 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Catch.Mods +{ + public class CatchModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Drain Rate", "Override the beatmap's set HP")] + public override BindableNumber DrainRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 1F, + }; + + [SettingSource("Fruit Size", "Override the beatmap's set CS")] + public override BindableNumber CircleSize { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + + [SettingSource("Approach Rate", "Override the beatmap's set AR")] + public override BindableNumber ApproachRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + + public override void ApplyToDifficulty(BeatmapDifficulty difficulty) + { + difficulty.DrainRate = DrainRate.Value; + difficulty.CircleSize = CircleSize.Value; + difficulty.ApproachRate = ApproachRate.Value; + difficulty.OverallDifficulty = ApproachRate.Value; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index c74a292331..c4908d1993 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -143,6 +143,7 @@ namespace osu.Game.Rulesets.Mania new ManiaModRandom(), new ManiaModDualStages(), new ManiaModMirror(), + new ManiaModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs new file mode 100644 index 0000000000..67e464f7d8 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Mania.Mods +{ + public class ManiaModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] + public override BindableNumber OverallDifficulty { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs new file mode 100644 index 0000000000..6851fe0d0a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Drain Rate", "Override the beatmap's set HP")] + public override BindableNumber DrainRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + + [SettingSource("Circle Size", "Override the beatmap's set CS")] + public override BindableNumber CircleSize { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + + [SettingSource("Approach Rate", "Override the beatmap's set AR")] + public override BindableNumber ApproachRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + + [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] + public override BindableNumber OverallDifficulty { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index fa69cec78d..746876b217 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -121,6 +121,7 @@ namespace osu.Game.Rulesets.Osu return new Mod[] { new OsuModTarget(), + new OsuModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs new file mode 100644 index 0000000000..611f74f707 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Taiko.Mods +{ + public class TaikoModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Drain Rate", "Override the beatmap's set HP")] + public override BindableNumber DrainRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + + [SettingSource("Approach Rate", "Override the beatmap's set AR")] + public override BindableNumber ApproachRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + + [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] + public override BindableNumber OverallDifficulty { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index b2655f592c..c4c85c183b 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -97,6 +97,12 @@ namespace osu.Game.Rulesets.Taiko new TaikoModFlashlight(), }; + case ModType.Conversion: + return new Mod[] + { + new TaikoModDifficultyAdjust(), + }; + case ModType.Automation: return new Mod[] { diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs new file mode 100644 index 0000000000..6e7233e4d0 --- /dev/null +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -0,0 +1,43 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Beatmaps; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Sprites; +using System; + +namespace osu.Game.Rulesets.Mods +{ + public abstract class ModDifficultyAdjust : Mod, IApplicableToDifficulty + { + public override string Name => @"Difficulty Adjust"; + + public override string Description => @"Override a beatmap's difficulty settings"; + + public override string Acronym => "DA"; + + public override ModType Type => ModType.Conversion; + + public override IconUsage Icon => FontAwesome.Solid.Hammer; + + public override double ScoreMultiplier => 1.0; + + public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModHardRock) }; + + public virtual BindableNumber DrainRate { get; } + + public virtual BindableNumber CircleSize { get; } + + public virtual BindableNumber ApproachRate { get; } + + public virtual BindableNumber OverallDifficulty { get; } + + public virtual void ApplyToDifficulty(BeatmapDifficulty difficulty) + { + difficulty.DrainRate = DrainRate != null ? DrainRate.Value : difficulty.DrainRate; + difficulty.CircleSize = CircleSize != null ? CircleSize.Value : difficulty.CircleSize; + difficulty.ApproachRate = ApproachRate != null ? ApproachRate.Value : difficulty.ApproachRate; + difficulty.OverallDifficulty = OverallDifficulty != null ? OverallDifficulty.Value: difficulty.OverallDifficulty; + } + } +} \ No newline at end of file From be3634cce16a53eca471d185218f5b168002a5e7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Dec 2019 20:02:23 +0800 Subject: [PATCH 18/86] remove ApproachRate setting --- .../Mods/TaikoModDifficultyAdjust.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs index 611f74f707..7b7bc69aad 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs @@ -19,16 +19,6 @@ namespace osu.Game.Rulesets.Taiko.Mods Precision = 0.1F, }; - [SettingSource("Approach Rate", "Override the beatmap's set AR")] - public override BindableNumber ApproachRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] public override BindableNumber OverallDifficulty { get; } = new BindableFloat { From b0cf44c3bedfa3973be04befbbd1b56771206acc Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Dec 2019 20:12:29 +0800 Subject: [PATCH 19/86] fix appveyor issues --- osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs | 2 +- osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs | 2 +- osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs | 2 +- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs index 7dfd5e8964..6643ebadf1 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs @@ -48,4 +48,4 @@ namespace osu.Game.Rulesets.Catch.Mods difficulty.OverallDifficulty = ApproachRate.Value; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs index 67e464f7d8..67554e6b92 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs @@ -19,4 +19,4 @@ namespace osu.Game.Rulesets.Mania.Mods Precision = 0.1F, }; } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index 6851fe0d0a..86ab4579bb 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -49,4 +49,4 @@ namespace osu.Game.Rulesets.Osu.Mods Precision = 0.1F, }; } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs index 7b7bc69aad..ed76cf77ac 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs @@ -29,4 +29,4 @@ namespace osu.Game.Rulesets.Taiko.Mods Precision = 0.1F, }; } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 6e7233e4d0..d1f6bf45b4 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mods difficulty.DrainRate = DrainRate != null ? DrainRate.Value : difficulty.DrainRate; difficulty.CircleSize = CircleSize != null ? CircleSize.Value : difficulty.CircleSize; difficulty.ApproachRate = ApproachRate != null ? ApproachRate.Value : difficulty.ApproachRate; - difficulty.OverallDifficulty = OverallDifficulty != null ? OverallDifficulty.Value: difficulty.OverallDifficulty; + difficulty.OverallDifficulty = OverallDifficulty != null ? OverallDifficulty.Value : difficulty.OverallDifficulty; } } -} \ No newline at end of file +} From 472fa9822cc7409487935ea6e0657e8c52a38594 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Dec 2019 08:25:51 +0800 Subject: [PATCH 20/86] make ModDifficultyAdjust incompatible with ModEasy and ModHardRock --- osu.Game/Rulesets/Mods/ModEasy.cs | 2 +- osu.Game/Rulesets/Mods/ModHardRock.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModEasy.cs b/osu.Game/Rulesets/Mods/ModEasy.cs index a55ebc51d6..7a34b2de3c 100644 --- a/osu.Game/Rulesets/Mods/ModEasy.cs +++ b/osu.Game/Rulesets/Mods/ModEasy.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mods public override ModType Type => ModType.DifficultyReduction; public override double ScoreMultiplier => 0.5; public override bool Ranked => true; - public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) }; + public override Type[] IncompatibleMods => new[] { typeof(ModHardRock), typeof(ModDifficultyAdjust) }; private int retries = 2; diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs index 2044cbeae2..2bcac3e4a9 100644 --- a/osu.Game/Rulesets/Mods/ModHardRock.cs +++ b/osu.Game/Rulesets/Mods/ModHardRock.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mods public override IconUsage Icon => OsuIcon.ModHardrock; public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Everything just got a bit harder..."; - public override Type[] IncompatibleMods => new[] { typeof(ModEasy) }; + public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModDifficultyAdjust) }; public void ApplyToDifficulty(BeatmapDifficulty difficulty) { From 81c849303853cdcc328793b39a440cc76844f477 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Dec 2019 12:16:19 +0300 Subject: [PATCH 21/86] Split combo colour decoding to small test cases --- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 69 ++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 003b3f5e56..cb2af359b9 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -13,43 +13,21 @@ namespace osu.Game.Tests.Skins [TestFixture] public class LegacySkinDecoderTest { - [TestCase(true)] - [TestCase(false)] - [TestCase(false, false)] - public void TestDecodeSkinColours(bool hasColours, bool canFallback = true) + public void TestDecodeSkinColours() { var decoder = new LegacySkinDecoder(); - using (var resStream = TestResources.OpenResource(hasColours ? "skin.ini" : "skin-empty.ini")) + using (var resStream = TestResources.OpenResource("skin.ini")) using (var stream = new LineBufferedReader(resStream)) { - var skinConfiguration = decoder.Decode(stream); - skinConfiguration.AllowDefaultComboColoursFallback = canFallback; - - var comboColors = skinConfiguration.ComboColours; - - if (!canFallback && !hasColours) + var comboColors = decoder.Decode(stream).ComboColours; + var expectedColors = new List { - Assert.IsNull(comboColors); - return; - } - - List expectedColors; - - if (hasColours) - { - expectedColors = new List - { - new Color4(142, 199, 255, 255), - new Color4(255, 128, 128, 255), - new Color4(128, 255, 255, 255), - new Color4(100, 100, 100, 100), - }; - } - else - { - expectedColors = SkinConfiguration.DefaultComboColours; - } + new Color4(142, 199, 255, 255), + new Color4(255, 128, 128, 255), + new Color4(128, 255, 255, 255), + new Color4(100, 100, 100, 100), + }; Assert.AreEqual(expectedColors.Count, comboColors.Count); for (int i = 0; i < expectedColors.Count; i++) @@ -57,6 +35,35 @@ namespace osu.Game.Tests.Skins } } + public void TestDecodeEmptySkinColours() + { + var decoder = new LegacySkinDecoder(); + + using (var resStream = TestResources.OpenResource("skin-empty.ini")) + using (var stream = new LineBufferedReader(resStream)) + { + var comboColors = decoder.Decode(stream).ComboColours; + var expectedColors = SkinConfiguration.DefaultComboColours; + + Assert.AreEqual(expectedColors.Count, comboColors.Count); + for (int i = 0; i < expectedColors.Count; i++) + Assert.AreEqual(expectedColors[i], comboColors[i]); + } + } + + public void TestDecodeEmptySkinColoursNoFallback() + { + var decoder = new LegacySkinDecoder(); + + using (var resStream = TestResources.OpenResource("skin-empty.ini")) + using (var stream = new LineBufferedReader(resStream)) + { + var skinConfiguration = decoder.Decode(stream); + skinConfiguration.AllowDefaultComboColoursFallback = false; + Assert.IsNull(skinConfiguration.ComboColours); + } + } + [Test] public void TestDecodeGeneral() { From ebd778da2de92377a1e1c874f294d73d0b90494a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Dec 2019 12:48:07 +0300 Subject: [PATCH 22/86] More test splitting --- .../Skins/TestSceneSkinConfigurationLookup.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index fe96cbd633..8808cf2185 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -117,9 +117,8 @@ namespace osu.Game.Tests.Skins }); } - [TestCase(false)] - [TestCase(true)] - public void TestEmptyComboColours(bool allowFallback) + [Test] + public void TestEmptyComboColours() { AddStep("Add custom combo colours to source1", () => source1.Configuration.ComboColours = new List { @@ -127,11 +126,25 @@ namespace osu.Game.Tests.Skins new Color4(55, 110, 166, 255), new Color4(75, 125, 175, 255), }); - AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = allowFallback); - AddAssert($"Check retrieved combo colours from {(allowFallback ? "source1" : "fallback source")}", () => + AddAssert("Check retrieved combo colours is skin default colours", () => + requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(SkinConfiguration.DefaultComboColours) ?? false); + } + + [Test] + public void TestEmptyComboColoursNoFallback() + { + AddStep("Add custom combo colours to source1", () => source1.Configuration.ComboColours = new List { - var expectedColours = allowFallback ? SkinConfiguration.DefaultComboColours : source1.Configuration.ComboColours; + new Color4(100, 150, 200, 255), + new Color4(55, 110, 166, 255), + new Color4(75, 125, 175, 255), + }); + AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = false); + + AddAssert("Check retrieved combo colours from source1", () => + { + var expectedColours = source1.Configuration.ComboColours; return requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(expectedColours) ?? false; }); } From bf8caee53fdbf9fc392462fea7dfdb549af0e7cb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Dec 2019 14:05:24 +0300 Subject: [PATCH 23/86] Inherit SkinConfiguration directly --- osu.Game/Skinning/LegacySkinConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkinConfiguration.cs b/osu.Game/Skinning/LegacySkinConfiguration.cs index b1679bd464..027f5b8883 100644 --- a/osu.Game/Skinning/LegacySkinConfiguration.cs +++ b/osu.Game/Skinning/LegacySkinConfiguration.cs @@ -3,7 +3,7 @@ namespace osu.Game.Skinning { - public class LegacySkinConfiguration : DefaultSkinConfiguration + public class LegacySkinConfiguration : SkinConfiguration { public const decimal LATEST_VERSION = 2.7m; From 4406172eb4151a367cabc659456c44f5822631b8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Dec 2019 14:05:37 +0300 Subject: [PATCH 24/86] Add missing test attributes --- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 8dbd894a0e..cef38bbbb8 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -13,6 +13,7 @@ namespace osu.Game.Tests.Skins [TestFixture] public class LegacySkinDecoderTest { + [Test] public void TestDecodeSkinColours() { var decoder = new LegacySkinDecoder(); @@ -35,6 +36,7 @@ namespace osu.Game.Tests.Skins } } + [Test] public void TestDecodeEmptySkinColours() { var decoder = new LegacySkinDecoder(); @@ -51,6 +53,7 @@ namespace osu.Game.Tests.Skins } } + [Test] public void TestDecodeEmptySkinColoursNoFallback() { var decoder = new LegacySkinDecoder(); From 7e1d21fa1658efcdf344f0ac632b7db83010847e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Dec 2019 14:08:35 +0300 Subject: [PATCH 25/86] Simplify combo colours lookup tests --- .../Skins/TestSceneSkinConfigurationLookup.cs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index 8808cf2185..ed54cc982d 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -120,13 +120,6 @@ namespace osu.Game.Tests.Skins [Test] public void TestEmptyComboColours() { - AddStep("Add custom combo colours to source1", () => source1.Configuration.ComboColours = new List - { - new Color4(100, 150, 200, 255), - new Color4(55, 110, 166, 255), - new Color4(75, 125, 175, 255), - }); - AddAssert("Check retrieved combo colours is skin default colours", () => requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(SkinConfiguration.DefaultComboColours) ?? false); } @@ -134,19 +127,16 @@ namespace osu.Game.Tests.Skins [Test] public void TestEmptyComboColoursNoFallback() { - AddStep("Add custom combo colours to source1", () => source1.Configuration.ComboColours = new List - { + AddStep("Add custom combo colours to source1", () => source1.Configuration.AddComboColours( new Color4(100, 150, 200, 255), new Color4(55, 110, 166, 255), - new Color4(75, 125, 175, 255), - }); + new Color4(75, 125, 175, 255) + )); + AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = false); AddAssert("Check retrieved combo colours from source1", () => - { - var expectedColours = source1.Configuration.ComboColours; - return requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(expectedColours) ?? false; - }); + requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(source1.Configuration.ComboColours) ?? false); } [Test] From 002a125b4aee43b6eac28581a784ffe1fecd21bd Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Dec 2019 21:14:26 +0800 Subject: [PATCH 26/86] make ModDifficultyAdjust generic --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../Mods/CatchModDifficultyAdjust.cs | 51 ------------------ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Mods/ManiaModDifficultyAdjust.cs | 22 -------- .../Mods/OsuModDifficultyAdjust.cs | 52 ------------------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- .../Mods/TaikoModDifficultyAdjust.cs | 32 ------------ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 51 ++++++++++++++---- 9 files changed, 46 insertions(+), 170 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs delete mode 100644 osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs delete mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs delete mode 100644 osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 6495c5379b..5973eea602 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Catch case ModType.Conversion: return new Mod[] { - new CatchModDifficultyAdjust(), + new ModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs deleted file mode 100644 index 6643ebadf1..0000000000 --- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Rulesets.Mods; - -namespace osu.Game.Rulesets.Catch.Mods -{ - public class CatchModDifficultyAdjust : ModDifficultyAdjust - { - [SettingSource("Drain Rate", "Override the beatmap's set HP")] - public override BindableNumber DrainRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 1F, - }; - - [SettingSource("Fruit Size", "Override the beatmap's set CS")] - public override BindableNumber CircleSize { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - - [SettingSource("Approach Rate", "Override the beatmap's set AR")] - public override BindableNumber ApproachRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - - public override void ApplyToDifficulty(BeatmapDifficulty difficulty) - { - difficulty.DrainRate = DrainRate.Value; - difficulty.CircleSize = CircleSize.Value; - difficulty.ApproachRate = ApproachRate.Value; - difficulty.OverallDifficulty = ApproachRate.Value; - } - } -} diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index c4908d1993..520bcfb586 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Mania new ManiaModRandom(), new ManiaModDualStages(), new ManiaModMirror(), - new ManiaModDifficultyAdjust(), + new ModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs deleted file mode 100644 index 67554e6b92..0000000000 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Game.Configuration; -using osu.Game.Rulesets.Mods; - -namespace osu.Game.Rulesets.Mania.Mods -{ - public class ManiaModDifficultyAdjust : ModDifficultyAdjust - { - [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] - public override BindableNumber OverallDifficulty { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs deleted file mode 100644 index 86ab4579bb..0000000000 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Game.Configuration; -using osu.Game.Rulesets.Mods; - -namespace osu.Game.Rulesets.Osu.Mods -{ - public class OsuModDifficultyAdjust : ModDifficultyAdjust - { - [SettingSource("Drain Rate", "Override the beatmap's set HP")] - public override BindableNumber DrainRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - - [SettingSource("Circle Size", "Override the beatmap's set CS")] - public override BindableNumber CircleSize { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - - [SettingSource("Approach Rate", "Override the beatmap's set AR")] - public override BindableNumber ApproachRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - - [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] - public override BindableNumber OverallDifficulty { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - } -} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 746876b217..b9fa14baa1 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Osu return new Mod[] { new OsuModTarget(), - new OsuModDifficultyAdjust(), + new ModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs deleted file mode 100644 index ed76cf77ac..0000000000 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Game.Configuration; -using osu.Game.Rulesets.Mods; - -namespace osu.Game.Rulesets.Taiko.Mods -{ - public class TaikoModDifficultyAdjust : ModDifficultyAdjust - { - [SettingSource("Drain Rate", "Override the beatmap's set HP")] - public override BindableNumber DrainRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - - [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] - public override BindableNumber OverallDifficulty { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; - } -} diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index c4c85c183b..40ce58aeca 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Taiko case ModType.Conversion: return new Mod[] { - new TaikoModDifficultyAdjust(), + new ModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index d1f6bf45b4..532da8a647 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -5,10 +5,11 @@ using osu.Game.Beatmaps; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using System; +using osu.Game.Configuration; namespace osu.Game.Rulesets.Mods { - public abstract class ModDifficultyAdjust : Mod, IApplicableToDifficulty + public class ModDifficultyAdjust : Mod, IApplicableToDifficulty { public override string Name => @"Difficulty Adjust"; @@ -24,20 +25,52 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModHardRock) }; - public virtual BindableNumber DrainRate { get; } + [SettingSource("Drain Rate", "Override the beatmap's set HP")] + public BindableNumber DrainRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; - public virtual BindableNumber CircleSize { get; } + [SettingSource("Circle Size", "Override the beatmap's set CS")] + public BindableNumber CircleSize { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; - public virtual BindableNumber ApproachRate { get; } + [SettingSource("Approach Rate", "Override the beatmap's set AR")] + public BindableNumber ApproachRate { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; - public virtual BindableNumber OverallDifficulty { get; } + [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] + public BindableNumber OverallDifficulty { get; } = new BindableFloat + { + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + Precision = 0.1F, + }; public virtual void ApplyToDifficulty(BeatmapDifficulty difficulty) { - difficulty.DrainRate = DrainRate != null ? DrainRate.Value : difficulty.DrainRate; - difficulty.CircleSize = CircleSize != null ? CircleSize.Value : difficulty.CircleSize; - difficulty.ApproachRate = ApproachRate != null ? ApproachRate.Value : difficulty.ApproachRate; - difficulty.OverallDifficulty = OverallDifficulty != null ? OverallDifficulty.Value : difficulty.OverallDifficulty; + difficulty.DrainRate = DrainRate.Value; + difficulty.CircleSize = CircleSize.Value; + difficulty.ApproachRate = ApproachRate.Value; + difficulty.OverallDifficulty = OverallDifficulty.Value; } } } From ababe7b6c995b2943ad71ce23d9734a62b412bcc Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 13 Dec 2019 15:22:07 +0800 Subject: [PATCH 27/86] refactor mod to make use of #7175 --- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 532da8a647..f65340e90c 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -65,12 +65,24 @@ namespace osu.Game.Rulesets.Mods Precision = 0.1F, }; + private BeatmapDifficulty difficulty; + public virtual void ApplyToDifficulty(BeatmapDifficulty difficulty) { - difficulty.DrainRate = DrainRate.Value; - difficulty.CircleSize = CircleSize.Value; - difficulty.ApproachRate = ApproachRate.Value; - difficulty.OverallDifficulty = OverallDifficulty.Value; + if (this.difficulty == null || this.difficulty.ID != difficulty.ID) + { + this.difficulty = difficulty; + DrainRate.Value = DrainRate.Default = difficulty.DrainRate; + CircleSize.Value = CircleSize.Default = difficulty.CircleSize; + ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; + OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; + } else + { + difficulty.DrainRate = DrainRate.Value; + difficulty.CircleSize = CircleSize.Value; + difficulty.ApproachRate = ApproachRate.Value; + difficulty.OverallDifficulty = OverallDifficulty.Value; + } } } } From 0311cc83ad1387d2191d104fab1617a5b4db347a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 13 Dec 2019 15:27:34 +0800 Subject: [PATCH 28/86] add whitespace --- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index f65340e90c..f6216df2b5 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -76,7 +76,8 @@ namespace osu.Game.Rulesets.Mods CircleSize.Value = CircleSize.Default = difficulty.CircleSize; ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; - } else + } + else { difficulty.DrainRate = DrainRate.Value; difficulty.CircleSize = CircleSize.Value; From ab5aa8594de8cf994834014885ae28818827030f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 13 Dec 2019 15:46:58 +0800 Subject: [PATCH 29/86] remove whitespace --- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index f6216df2b5..b23297345b 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Mods CircleSize.Value = CircleSize.Default = difficulty.CircleSize; ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; - } + } else { difficulty.DrainRate = DrainRate.Value; From 1da8cc86900a3f3538f6c2b7d4edcaa10fcc4f13 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Dec 2019 19:02:11 +0900 Subject: [PATCH 30/86] Encapsulate common logic of ScoreProcessor --- .../Rulesets/Scoring/JudgementProcessor.cs | 126 +++++++++++++++++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 129 +++--------------- 2 files changed, 146 insertions(+), 109 deletions(-) create mode 100644 osu.Game/Rulesets/Scoring/JudgementProcessor.cs diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs new file mode 100644 index 0000000000..854b926846 --- /dev/null +++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs @@ -0,0 +1,126 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Extensions.TypeExtensions; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Scoring +{ + public abstract class JudgementProcessor + { + /// + /// The maximum number of hits that can be judged. + /// + protected int MaxHits { get; private set; } + + /// + /// The total number of judged s at the current point in time. + /// + public int JudgedHits { get; private set; } + + protected JudgementProcessor(IBeatmap beatmap) + { + ApplyBeatmap(beatmap); + + Reset(false); + SimulateAutoplay(beatmap); + Reset(true); + } + + /// + /// Applies any properties of the which affect scoring to this . + /// + /// The to read properties from. + protected virtual void ApplyBeatmap(IBeatmap beatmap) + { + } + + /// + /// Applies the score change of a to this . + /// + /// The to apply. + public void ApplyResult(JudgementResult result) + { + JudgedHits++; + + ApplyResultInternal(result); + } + + /// + /// Reverts the score change of a that was applied to this . + /// + /// The judgement scoring result. + public void RevertResult(JudgementResult result) + { + JudgedHits--; + + RevertResultInternal(result); + } + + /// + /// Applies the score change of a to this . + /// + /// + /// Any changes applied via this method can be reverted via . + /// + /// The to apply. + protected abstract void ApplyResultInternal(JudgementResult result); + + /// + /// Reverts the score change of a that was applied to this via . + /// + /// The judgement scoring result. + protected abstract void RevertResultInternal(JudgementResult result); + + /// + /// Resets this to a default state. + /// + /// Whether to store the current state of the for future use. + protected virtual void Reset(bool storeResults) + { + if (storeResults) + MaxHits = JudgedHits; + + JudgedHits = 0; + } + + /// + /// Creates the that represents the scoring result for a . + /// + /// The which was judged. + /// The that provides the scoring information. + protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement); + + /// + /// Simulates an autoplay of the to determine scoring values. + /// + /// This provided temporarily. DO NOT USE. + /// The to simulate. + protected virtual void SimulateAutoplay(IBeatmap beatmap) + { + foreach (var obj in beatmap.HitObjects) + simulate(obj); + + void simulate(HitObject obj) + { + foreach (var nested in obj.NestedHitObjects) + simulate(nested); + + var judgement = obj.CreateJudgement(); + if (judgement == null) + return; + + var result = CreateResult(obj, judgement); + if (result == null) + throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); + + result.Type = judgement.MaxResult; + + ApplyResult(result); + } + } + } +} diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index a8a2294498..f885a860ec 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Extensions; -using osu.Framework.Extensions.TypeExtensions; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; @@ -17,7 +16,7 @@ using osu.Game.Scoring; namespace osu.Game.Rulesets.Scoring { - public class ScoreProcessor + public class ScoreProcessor : JudgementProcessor { private const double base_portion = 0.3; private const double combo_portion = 0.7; @@ -95,16 +94,6 @@ namespace osu.Game.Rulesets.Scoring /// public bool HasFailed { get; private set; } - /// - /// The maximum number of hits that can be judged. - /// - protected int MaxHits { get; private set; } - - /// - /// The total number of judged s at the current point in time. - /// - public int JudgedHits { get; private set; } - private double maxHighestCombo; private double maxBaseScore; @@ -115,8 +104,14 @@ namespace osu.Game.Rulesets.Scoring private double scoreMultiplier = 1; public ScoreProcessor(IBeatmap beatmap) + : base(beatmap) { Debug.Assert(base_portion + combo_portion == 1.0); + } + + protected override void ApplyBeatmap(IBeatmap beatmap) + { + base.ApplyBeatmap(beatmap); Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue); Accuracy.ValueChanged += accuracy => @@ -126,12 +121,6 @@ namespace osu.Game.Rulesets.Scoring Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue); }; - ApplyBeatmap(beatmap); - - Reset(false); - SimulateAutoplay(beatmap); - Reset(true); - if (maxBaseScore == 0 || maxHighestCombo == 0) { Mode.Value = ScoringMode.Classic; @@ -150,80 +139,9 @@ namespace osu.Game.Rulesets.Scoring }; } - /// - /// Applies any properties of the which affect scoring to this . - /// - /// The to read properties from. - protected virtual void ApplyBeatmap(IBeatmap beatmap) - { - } - - /// - /// Simulates an autoplay of the to determine scoring values. - /// - /// This provided temporarily. DO NOT USE. - /// The to simulate. - protected virtual void SimulateAutoplay(IBeatmap beatmap) - { - foreach (var obj in beatmap.HitObjects) - simulate(obj); - - void simulate(HitObject obj) - { - foreach (var nested in obj.NestedHitObjects) - simulate(nested); - - var judgement = obj.CreateJudgement(); - if (judgement == null) - return; - - var result = CreateResult(obj, judgement); - if (result == null) - throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); - - result.Type = judgement.MaxResult; - - ApplyResult(result); - } - } - - /// - /// Applies the score change of a to this . - /// - /// The to apply. - public void ApplyResult(JudgementResult result) - { - ApplyResultInternal(result); - - updateScore(); - updateFailed(result); - - NewJudgement?.Invoke(result); - - if (HasCompleted) - AllJudged?.Invoke(); - } - - /// - /// Reverts the score change of a that was applied to this . - /// - /// The judgement scoring result. - public void RevertResult(JudgementResult result) - { - RevertResultInternal(result); - updateScore(); - } - private readonly Dictionary scoreResultCounts = new Dictionary(); - /// - /// Applies the score change of a to this . - /// - /// - /// Any changes applied via this method can be reverted via . - /// - /// The to apply. - protected virtual void ApplyResultInternal(JudgementResult result) + protected sealed override void ApplyResultInternal(JudgementResult result) { result.ComboAtJudgement = Combo.Value; result.HighestComboAtJudgement = HighestCombo.Value; @@ -233,8 +151,6 @@ namespace osu.Game.Rulesets.Scoring if (HasFailed) return; - JudgedHits++; - if (result.Judgement.AffectsCombo) { switch (result.Type) @@ -267,13 +183,17 @@ namespace osu.Game.Rulesets.Scoring } Health.Value += HealthAdjustmentFactorFor(result) * result.Judgement.HealthIncreaseFor(result); + + updateScore(); + updateFailed(result); + + NewJudgement?.Invoke(result); + + if (HasCompleted) + AllJudged?.Invoke(); } - /// - /// Reverts the score change of a that was applied to this via . - /// - /// The judgement scoring result. - protected virtual void RevertResultInternal(JudgementResult result) + protected sealed override void RevertResultInternal(JudgementResult result) { Combo.Value = result.ComboAtJudgement; HighestCombo.Value = result.HighestComboAtJudgement; @@ -284,8 +204,6 @@ namespace osu.Game.Rulesets.Scoring if (result.FailedAtJudgement) return; - JudgedHits--; - if (result.Judgement.IsBonus) { if (result.IsHit) @@ -372,18 +290,18 @@ namespace osu.Game.Rulesets.Scoring /// Resets this ScoreProcessor to a default state. /// /// Whether to store the current state of the for future use. - protected virtual void Reset(bool storeResults) + protected override void Reset(bool storeResults) { + base.Reset(storeResults); + scoreResultCounts.Clear(); if (storeResults) { - MaxHits = JudgedHits; maxHighestCombo = HighestCombo.Value; maxBaseScore = baseScore; } - JudgedHits = 0; baseScore = 0; rollingMaxBaseScore = 0; bonusScore = 0; @@ -425,13 +343,6 @@ namespace osu.Game.Rulesets.Scoring /// Create a for this processor. /// public virtual HitWindows CreateHitWindows() => new HitWindows(); - - /// - /// Creates the that represents the scoring result for a . - /// - /// The which was judged. - /// The that provides the scoring information. - protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement); } public enum ScoringMode From 76f2fb378fbbed997505b64fd2a6624270a32704 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Dec 2019 20:03:14 +0900 Subject: [PATCH 31/86] Separate score and health parts of ScoreProcessor --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 + .../Scoring/CatchHealthProcessor.cs | 38 +++++++ .../Scoring/CatchScoreProcessor.cs | 22 ---- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 + .../Scoring/ManiaHealthProcessor.cs | 69 ++++++++++++ .../Scoring/ManiaScoreProcessor.cs | 69 ------------ osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 6 +- .../Scoring/OsuHealthProcessor.cs | 54 ++++++++++ .../Scoring/OsuScoreProcessor.cs | 33 ------ .../Scoring/TaikoHealthProcessor.cs | 58 ++++++++++ .../Scoring/TaikoScoreProcessor.cs | 42 -------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 + .../Visual/Gameplay/TestSceneFailAnimation.cs | 2 +- .../Visual/Gameplay/TestSceneFailJudgement.cs | 2 +- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- .../Visual/Gameplay/TestScenePause.cs | 8 +- .../Mods/IApplicableToHealthProcessor.cs | 15 +++ osu.Game/Rulesets/Mods/ModEasy.cs | 9 +- osu.Game/Rulesets/Mods/ModPerfect.cs | 2 +- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 11 +- osu.Game/Rulesets/Ruleset.cs | 6 ++ osu.Game/Rulesets/Scoring/HealthProcessor.cs | 102 ++++++++++++++++++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 66 +----------- osu.Game/Screens/Play/HUDOverlay.cs | 17 ++- osu.Game/Screens/Play/Player.cs | 30 ++++-- 25 files changed, 404 insertions(+), 265 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Scoring/CatchHealthProcessor.cs create mode 100644 osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs create mode 100644 osu.Game.Rulesets.Osu/Scoring/OsuHealthProcessor.cs create mode 100644 osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs create mode 100644 osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs create mode 100644 osu.Game/Rulesets/Scoring/HealthProcessor.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index b8a844cb86..26e6112f83 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Catch public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new CatchScoreProcessor(beatmap); + public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new CatchHealthProcessor(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap); diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchHealthProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchHealthProcessor.cs new file mode 100644 index 0000000000..49ba0f6122 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Scoring/CatchHealthProcessor.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Catch.Scoring +{ + public class CatchHealthProcessor : HealthProcessor + { + public CatchHealthProcessor(IBeatmap beatmap) + : base(beatmap) + { + } + + private float hpDrainRate; + + protected override void ApplyBeatmap(IBeatmap beatmap) + { + base.ApplyBeatmap(beatmap); + + hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate; + } + + protected override double HealthAdjustmentFactorFor(JudgementResult result) + { + switch (result.Type) + { + case HitResult.Miss: + return hpDrainRate; + + default: + return 10.2 - hpDrainRate; // Award less HP as drain rate is increased + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index f67ca1213e..ad7520d57d 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Beatmaps; -using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Catch.Scoring @@ -14,27 +13,6 @@ namespace osu.Game.Rulesets.Catch.Scoring { } - private float hpDrainRate; - - protected override void ApplyBeatmap(IBeatmap beatmap) - { - base.ApplyBeatmap(beatmap); - - hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate; - } - - protected override double HealthAdjustmentFactorFor(JudgementResult result) - { - switch (result.Type) - { - case HitResult.Miss: - return hpDrainRate; - - default: - return 10.2 - hpDrainRate; // Award less HP as drain rate is increased - } - } - public override HitWindows CreateHitWindows() => new CatchHitWindows(); } } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index bf630cf892..0ec1264cce 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Mania public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ManiaScoreProcessor(beatmap); + public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new ManiaHealthProcessor(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score); diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs new file mode 100644 index 0000000000..c362c906a4 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs @@ -0,0 +1,69 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Mania.Scoring +{ + public class ManiaHealthProcessor : HealthProcessor + { + /// + /// The hit HP multiplier at OD = 0. + /// + private const double hp_multiplier_min = 0.75; + + /// + /// The hit HP multiplier at OD = 0. + /// + private const double hp_multiplier_mid = 0.85; + + /// + /// The hit HP multiplier at OD = 0. + /// + private const double hp_multiplier_max = 1; + + /// + /// The MISS HP multiplier at OD = 0. + /// + private const double hp_multiplier_miss_min = 0.5; + + /// + /// The MISS HP multiplier at OD = 5. + /// + private const double hp_multiplier_miss_mid = 0.75; + + /// + /// The MISS HP multiplier at OD = 10. + /// + private const double hp_multiplier_miss_max = 1; + + /// + /// The MISS HP multiplier. This is multiplied to the miss hp increase. + /// + private double hpMissMultiplier = 1; + + /// + /// The HIT HP multiplier. This is multiplied to hit hp increases. + /// + private double hpMultiplier = 1; + + public ManiaHealthProcessor(IBeatmap beatmap) + : base(beatmap) + { + } + + protected override void ApplyBeatmap(IBeatmap beatmap) + { + base.ApplyBeatmap(beatmap); + + BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BaseDifficulty; + hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max); + hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max); + } + + protected override double HealthAdjustmentFactorFor(JudgementResult result) + => result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier; + } +} diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index a678ef60e7..97f1ea721c 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -2,86 +2,17 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Beatmaps; -using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Scoring { internal class ManiaScoreProcessor : ScoreProcessor { - /// - /// The hit HP multiplier at OD = 0. - /// - private const double hp_multiplier_min = 0.75; - - /// - /// The hit HP multiplier at OD = 0. - /// - private const double hp_multiplier_mid = 0.85; - - /// - /// The hit HP multiplier at OD = 0. - /// - private const double hp_multiplier_max = 1; - - /// - /// The MISS HP multiplier at OD = 0. - /// - private const double hp_multiplier_miss_min = 0.5; - - /// - /// The MISS HP multiplier at OD = 5. - /// - private const double hp_multiplier_miss_mid = 0.75; - - /// - /// The MISS HP multiplier at OD = 10. - /// - private const double hp_multiplier_miss_max = 1; - - /// - /// The MISS HP multiplier. This is multiplied to the miss hp increase. - /// - private double hpMissMultiplier = 1; - - /// - /// The HIT HP multiplier. This is multiplied to hit hp increases. - /// - private double hpMultiplier = 1; - public ManiaScoreProcessor(IBeatmap beatmap) : base(beatmap) { } - protected override void ApplyBeatmap(IBeatmap beatmap) - { - base.ApplyBeatmap(beatmap); - - BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BaseDifficulty; - hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max); - hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max); - } - - protected override void SimulateAutoplay(IBeatmap beatmap) - { - while (true) - { - base.SimulateAutoplay(beatmap); - - if (!HasFailed) - break; - - hpMultiplier *= 1.01; - hpMissMultiplier *= 0.98; - - Reset(false); - } - } - - protected override double HealthAdjustmentFactorFor(JudgementResult result) - => result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier; - public override HitWindows CreateHitWindows() => new ManiaHitWindows(); } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 63110b2797..831e4a700f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModBlinds : Mod, IApplicableToDrawableRuleset, IApplicableToScoreProcessor + public class OsuModBlinds : Mod, IApplicableToDrawableRuleset, IApplicableToHealthProcessor { public override string Name => "Blinds"; public override string Description => "Play with blinds on your screen."; @@ -37,9 +37,9 @@ namespace osu.Game.Rulesets.Osu.Mods drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield.HitObjectContainer, drawableRuleset.Beatmap)); } - public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + public void ApplyToHealthProcessor(HealthProcessor healthProcessor) { - scoreProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); }; + healthProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); }; } public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuHealthProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuHealthProcessor.cs new file mode 100644 index 0000000000..36ccc80af6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Scoring/OsuHealthProcessor.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Osu.Scoring +{ + public class OsuHealthProcessor : HealthProcessor + { + public OsuHealthProcessor(IBeatmap beatmap) + : base(beatmap) + { + } + + private float hpDrainRate; + + protected override void ApplyBeatmap(IBeatmap beatmap) + { + base.ApplyBeatmap(beatmap); + + hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate; + } + + protected override double HealthAdjustmentFactorFor(JudgementResult result) + { + switch (result.Type) + { + case HitResult.Great: + return 10.2 - hpDrainRate; + + case HitResult.Good: + return 8 - hpDrainRate; + + case HitResult.Meh: + return 4 - hpDrainRate; + + // case HitResult.SliderTick: + // return Math.Max(7 - hpDrainRate, 0) * 0.01; + + case HitResult.Miss: + return hpDrainRate; + + default: + return 0; + } + } + + protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement); + } +} diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 6779271cb3..4593364e42 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -16,39 +16,6 @@ namespace osu.Game.Rulesets.Osu.Scoring { } - private float hpDrainRate; - - protected override void ApplyBeatmap(IBeatmap beatmap) - { - base.ApplyBeatmap(beatmap); - - hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate; - } - - protected override double HealthAdjustmentFactorFor(JudgementResult result) - { - switch (result.Type) - { - case HitResult.Great: - return 10.2 - hpDrainRate; - - case HitResult.Good: - return 8 - hpDrainRate; - - case HitResult.Meh: - return 4 - hpDrainRate; - - // case HitResult.SliderTick: - // return Math.Max(7 - hpDrainRate, 0) * 0.01; - - case HitResult.Miss: - return hpDrainRate; - - default: - return 0; - } - } - protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement); public override HitWindows CreateHitWindows() => new OsuHitWindows(); diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs new file mode 100644 index 0000000000..c8aa32a678 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.Scoring +{ + public class TaikoHealthProcessor : HealthProcessor + { + /// + /// A value used for calculating . + /// + private const double object_count_factor = 3; + + /// + /// Taiko fails at the end of the map if the player has not half-filled their HP bar. + /// + protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5; + + /// + /// HP multiplier for a successful . + /// + private double hpMultiplier; + + /// + /// HP multiplier for a . + /// + private double hpMissMultiplier; + + public TaikoHealthProcessor(IBeatmap beatmap) + : base(beatmap) + { + } + + protected override void ApplyBeatmap(IBeatmap beatmap) + { + base.ApplyBeatmap(beatmap); + + hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); + + hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120); + } + + protected override double HealthAdjustmentFactorFor(JudgementResult result) + => result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier; + + protected override void Reset(bool storeResults) + { + base.Reset(storeResults); + + Health.Value = 0; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index ae593d2e3a..10011d2669 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -1,60 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Scoring { internal class TaikoScoreProcessor : ScoreProcessor { - /// - /// A value used for calculating . - /// - private const double object_count_factor = 3; - - /// - /// Taiko fails at the end of the map if the player has not half-filled their HP bar. - /// - protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5; - - /// - /// HP multiplier for a successful . - /// - private double hpMultiplier; - - /// - /// HP multiplier for a . - /// - private double hpMissMultiplier; - public TaikoScoreProcessor(IBeatmap beatmap) : base(beatmap) { } - protected override void ApplyBeatmap(IBeatmap beatmap) - { - base.ApplyBeatmap(beatmap); - - hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); - - hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120); - } - - protected override double HealthAdjustmentFactorFor(JudgementResult result) - => result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier; - - protected override void Reset(bool storeResults) - { - base.Reset(storeResults); - - Health.Value = 0; - } - public override HitWindows CreateHitWindows() => new TaikoHitWindows(); } } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index ca7ab30867..0644f7fea6 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Taiko public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new TaikoScoreProcessor(beatmap); + public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new TaikoHealthProcessor(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap); public const string SHORT_NAME = "taiko"; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs index 992c47f856..81050b1637 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void LoadComplete() { base.LoadComplete(); - ScoreProcessor.FailConditions += (_, __) => true; + HealthProcessor.FailConditions += (_, __) => true; } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs index 1580aac8c5..a0c25521a6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void LoadComplete() { base.LoadComplete(); - ScoreProcessor.FailConditions += (_, __) => true; + HealthProcessor.FailConditions += (_, __) => true; } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 39c42980ab..ee58219cd3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("create overlay", () => { - Child = hudOverlay = new HUDOverlay(null, null, Array.Empty()); + Child = hudOverlay = new HUDOverlay(null, null, null, Array.Empty()); action?.Invoke(hudOverlay); }); diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index e04315894e..1a83e35e4f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestResumeWithResumeOverlay() { AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); - AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1); + AddUntilStep("wait for hitobjects", () => Player.HealthProcessor.Health.Value < 1); pauseAndConfirm(); resume(); @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestPauseWithResumeOverlay() { AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); - AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1); + AddUntilStep("wait for hitobjects", () => Player.HealthProcessor.Health.Value < 1); pauseAndConfirm(); @@ -92,7 +92,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("move cursor to button", () => InputManager.MoveMouseTo(Player.HUDOverlay.HoldToQuit.Children.OfType().First().ScreenSpaceDrawQuad.Centre)); - AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1); + AddUntilStep("wait for hitobjects", () => Player.HealthProcessor.Health.Value < 1); pauseAndConfirm(); resumeAndConfirm(); @@ -285,7 +285,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected class PausePlayer : TestPlayer { - public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + public new HealthProcessor HealthProcessor => base.HealthProcessor; public new HUDOverlay HUDOverlay => base.HUDOverlay; diff --git a/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs b/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs new file mode 100644 index 0000000000..a181955653 --- /dev/null +++ b/osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Mods +{ + public interface IApplicableToHealthProcessor : IApplicableMod + { + /// + /// Provide a to a mod. Called once on initialisation of a play instance. + /// + void ApplyToHealthProcessor(HealthProcessor healthProcessor); + } +} diff --git a/osu.Game/Rulesets/Mods/ModEasy.cs b/osu.Game/Rulesets/Mods/ModEasy.cs index a55ebc51d6..494bebbf10 100644 --- a/osu.Game/Rulesets/Mods/ModEasy.cs +++ b/osu.Game/Rulesets/Mods/ModEasy.cs @@ -7,11 +7,10 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; namespace osu.Game.Rulesets.Mods { - public abstract class ModEasy : Mod, IApplicableToDifficulty, IApplicableFailOverride, IApplicableToScoreProcessor + public abstract class ModEasy : Mod, IApplicableToDifficulty, IApplicableFailOverride, IApplicableToHealthProcessor { public override string Name => "Easy"; public override string Acronym => "EZ"; @@ -49,11 +48,9 @@ namespace osu.Game.Rulesets.Mods public bool RestartOnFail => false; - public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + public void ApplyToHealthProcessor(HealthProcessor healthProcessor) { - health = scoreProcessor.Health.GetBoundCopy(); + health = healthProcessor.Health.GetBoundCopy(); } - - public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } } diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index 0994d1f7d3..afa263f1c9 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Mods public override IconUsage Icon => OsuIcon.ModPerfect; public override string Description => "SS or quit."; - protected override bool FailCondition(ScoreProcessor scoreProcessor, JudgementResult result) => scoreProcessor.Accuracy.Value != 1; + protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => result.Type != result.Judgement.MaxResult; } } diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index c4c4ab1f04..a4d0631d8c 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -6,11 +6,10 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; namespace osu.Game.Rulesets.Mods { - public abstract class ModSuddenDeath : Mod, IApplicableToScoreProcessor, IApplicableFailOverride + public abstract class ModSuddenDeath : Mod, IApplicableToHealthProcessor, IApplicableFailOverride { public override string Name => "Sudden Death"; public override string Acronym => "SD"; @@ -24,13 +23,11 @@ namespace osu.Game.Rulesets.Mods public bool AllowFail => true; public bool RestartOnFail => true; - public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + public void ApplyToHealthProcessor(HealthProcessor healthProcessor) { - scoreProcessor.FailConditions += FailCondition; + healthProcessor.FailConditions += FailCondition; } - public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; - - protected virtual bool FailCondition(ScoreProcessor scoreProcessor, JudgementResult result) => scoreProcessor.Combo.Value == 0 && result.Judgement.AffectsCombo; + protected virtual bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => !result.IsHit && result.Judgement.AffectsCombo; } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 7ad93379f0..a98412b434 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -69,6 +69,12 @@ namespace osu.Game.Rulesets /// The score processor. public virtual ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ScoreProcessor(beatmap); + /// + /// Creates a for a beatmap converted to this ruleset. + /// + /// The health processor. + public virtual HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new HealthProcessor(beatmap); + /// /// Creates a to convert a to one that is applicable for this . /// diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs new file mode 100644 index 0000000000..8af8177083 --- /dev/null +++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs @@ -0,0 +1,102 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Bindables; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; + +namespace osu.Game.Rulesets.Scoring +{ + public class HealthProcessor : JudgementProcessor + { + /// + /// Invoked when the is in a failed state. + /// Return true if the fail was permitted. + /// + public event Func Failed; + + /// + /// Additional conditions on top of that cause a failing state. + /// + public event Func FailConditions; + + /// + /// The current health. + /// + public readonly BindableDouble Health = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; + + /// + /// Whether this ScoreProcessor has already triggered the failed state. + /// + public bool HasFailed { get; private set; } + + public HealthProcessor(IBeatmap beatmap) + : base(beatmap) + { + } + + protected override void ApplyResultInternal(JudgementResult result) + { + result.HealthAtJudgement = Health.Value; + result.FailedAtJudgement = HasFailed; + + if (HasFailed) + return; + + Health.Value += HealthAdjustmentFactorFor(result) * result.Judgement.HealthIncreaseFor(result); + + if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true) + return; + + if (Failed?.Invoke() != false) + HasFailed = true; + } + + protected override void RevertResultInternal(JudgementResult result) + { + Health.Value = result.HealthAtJudgement; + + // Todo: Revert HasFailed state with proper player support + } + + /// + /// An adjustment factor which is multiplied into the health increase provided by a . + /// + /// The for which the adjustment should apply. + /// The adjustment factor. + protected virtual double HealthAdjustmentFactorFor(JudgementResult result) => 1; + + /// + /// The default conditions for failing. + /// + protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value); + + protected override void Reset(bool storeResults) + { + base.Reset(storeResults); + + Health.Value = 1; + HasFailed = false; + } + + /// + /// Checks if the score is in a failed state and notifies subscribers. + /// + /// This can only ever notify subscribers once. + /// + /// + private void updateFailed(JudgementResult result) + { + if (HasFailed) + return; + + if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true) + return; + + if (Failed?.Invoke() != false) + HasFailed = true; + } + } +} diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index f885a860ec..945c21e196 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Extensions; -using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; @@ -22,13 +21,6 @@ namespace osu.Game.Rulesets.Scoring private const double combo_portion = 0.7; private const double max_score = 1000000; - /// - /// Invoked when the is in a failed state. - /// This may occur regardless of whether an event is invoked. - /// Return true if the fail was permitted. - /// - public event Func Failed; - /// /// Invoked when all s have been judged. /// @@ -39,11 +31,6 @@ namespace osu.Game.Rulesets.Scoring /// public event Action NewJudgement; - /// - /// Additional conditions on top of that cause a failing state. - /// - public event Func FailConditions; - /// /// The current total score. /// @@ -54,11 +41,6 @@ namespace osu.Game.Rulesets.Scoring /// public readonly BindableDouble Accuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; - /// - /// The current health. - /// - public readonly BindableDouble Health = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; - /// /// The current combo. /// @@ -89,11 +71,6 @@ namespace osu.Game.Rulesets.Scoring /// public bool HasCompleted => JudgedHits == MaxHits; - /// - /// Whether this ScoreProcessor has already triggered the failed state. - /// - public bool HasFailed { get; private set; } - private double maxHighestCombo; private double maxBaseScore; @@ -145,10 +122,8 @@ namespace osu.Game.Rulesets.Scoring { result.ComboAtJudgement = Combo.Value; result.HighestComboAtJudgement = HighestCombo.Value; - result.HealthAtJudgement = Health.Value; - result.FailedAtJudgement = HasFailed; - if (HasFailed) + if (result.FailedAtJudgement) return; if (result.Judgement.AffectsCombo) @@ -182,10 +157,7 @@ namespace osu.Game.Rulesets.Scoring rollingMaxBaseScore += result.Judgement.MaxNumericResult; } - Health.Value += HealthAdjustmentFactorFor(result) * result.Judgement.HealthIncreaseFor(result); - updateScore(); - updateFailed(result); NewJudgement?.Invoke(result); @@ -197,9 +169,6 @@ namespace osu.Game.Rulesets.Scoring { Combo.Value = result.ComboAtJudgement; HighestCombo.Value = result.HighestComboAtJudgement; - Health.Value = result.HealthAtJudgement; - - // Todo: Revert HasFailed state with proper player support if (result.FailedAtJudgement) return; @@ -219,13 +188,6 @@ namespace osu.Game.Rulesets.Scoring } } - /// - /// An adjustment factor which is multiplied into the health increase provided by a . - /// - /// The for which the adjustment should apply. - /// The adjustment factor. - protected virtual double HealthAdjustmentFactorFor(JudgementResult result) => 1; - private void updateScore() { if (rollingMaxBaseScore != 0) @@ -248,24 +210,6 @@ namespace osu.Game.Rulesets.Scoring } } - /// - /// Checks if the score is in a failed state and notifies subscribers. - /// - /// This can only ever notify subscribers once. - /// - /// - private void updateFailed(JudgementResult result) - { - if (HasFailed) - return; - - if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true) - return; - - if (Failed?.Invoke() != false) - HasFailed = true; - } - private ScoreRank rankFrom(double acc) { if (acc == 1) @@ -308,12 +252,9 @@ namespace osu.Game.Rulesets.Scoring TotalScore.Value = 0; Accuracy.Value = 1; - Health.Value = 1; Combo.Value = 0; Rank.Value = ScoreRank.X; HighestCombo.Value = 0; - - HasFailed = false; } /// @@ -334,11 +275,6 @@ namespace osu.Game.Rulesets.Scoring score.Statistics[result] = GetStatistic(result); } - /// - /// The default conditions for failing. - /// - protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value); - /// /// Create a for this processor. /// diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index e2f362780d..236bdc8442 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -41,6 +41,7 @@ namespace osu.Game.Screens.Play public Bindable ShowHealthbar = new Bindable(true); private readonly ScoreProcessor scoreProcessor; + private readonly HealthProcessor healthProcessor; private readonly DrawableRuleset drawableRuleset; private readonly IReadOnlyList mods; @@ -63,9 +64,10 @@ namespace osu.Game.Screens.Play private IEnumerable hideTargets => new Drawable[] { visibilityContainer, KeyCounter }; - public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList mods) + public HUDOverlay(ScoreProcessor scoreProcessor, HealthProcessor healthProcessor, DrawableRuleset drawableRuleset, IReadOnlyList mods) { this.scoreProcessor = scoreProcessor; + this.healthProcessor = healthProcessor; this.drawableRuleset = drawableRuleset; this.mods = mods; @@ -119,7 +121,10 @@ namespace osu.Game.Screens.Play private void load(OsuConfigManager config, NotificationOverlay notificationOverlay) { if (scoreProcessor != null) - BindProcessor(scoreProcessor); + BindScoreProcessor(scoreProcessor); + + if (healthProcessor != null) + BindHealthProcessor(healthProcessor); if (drawableRuleset != null) { @@ -288,15 +293,19 @@ namespace osu.Game.Screens.Play protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); - protected virtual void BindProcessor(ScoreProcessor processor) + protected virtual void BindScoreProcessor(ScoreProcessor processor) { ScoreCounter?.Current.BindTo(processor.TotalScore); AccuracyCounter?.Current.BindTo(processor.Accuracy); ComboCounter?.Current.BindTo(processor.Combo); - HealthDisplay?.Current.BindTo(processor.Health); if (HealthDisplay is StandardHealthDisplay shd) processor.NewJudgement += shd.Flash; } + + protected virtual void BindHealthProcessor(HealthProcessor processor) + { + HealthDisplay?.Current.BindTo(processor.Health); + } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5dfdeb5ebc..b64604728c 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -72,6 +72,9 @@ namespace osu.Game.Screens.Play public BreakOverlay BreakOverlay; protected ScoreProcessor ScoreProcessor { get; private set; } + + protected HealthProcessor HealthProcessor { get; private set; } + protected DrawableRuleset DrawableRuleset { get; private set; } protected HUDOverlay HUDOverlay { get; private set; } @@ -131,6 +134,8 @@ namespace osu.Game.Screens.Play ScoreProcessor = ruleset.CreateScoreProcessor(playableBeatmap); ScoreProcessor.Mods.BindTo(Mods); + HealthProcessor = ruleset.CreateHealthProcessor(playableBeatmap); + if (!ScoreProcessor.Mode.Disabled) config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); @@ -145,15 +150,28 @@ namespace osu.Game.Screens.Play // bind clock into components that require it DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused); - DrawableRuleset.OnNewResult += ScoreProcessor.ApplyResult; - DrawableRuleset.OnRevertResult += ScoreProcessor.RevertResult; + DrawableRuleset.OnNewResult += r => + { + HealthProcessor.ApplyResult(r); + ScoreProcessor.ApplyResult(r); + }; - // Bind ScoreProcessor to ourselves + DrawableRuleset.OnRevertResult += r => + { + HealthProcessor.RevertResult(r); + ScoreProcessor.RevertResult(r); + }; + + // Bind the judgement processors to ourselves ScoreProcessor.AllJudged += onCompletion; - ScoreProcessor.Failed += onFail; + HealthProcessor.Failed += onFail; foreach (var mod in Mods.Value.OfType()) mod.ApplyToScoreProcessor(ScoreProcessor); + + foreach (var mod in Mods.Value.OfType()) + mod.ApplyToHealthProcessor(HealthProcessor); + BreakOverlay.IsBreakTime.ValueChanged += _ => updatePauseOnFocusLostState(); } @@ -197,7 +215,7 @@ namespace osu.Game.Screens.Play // display the cursor above some HUD elements. DrawableRuleset.Cursor?.CreateProxy() ?? new Container(), DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(), - HUDOverlay = new HUDOverlay(ScoreProcessor, DrawableRuleset, Mods.Value) + HUDOverlay = new HUDOverlay(ScoreProcessor, HealthProcessor, DrawableRuleset, Mods.Value) { HoldToQuit = { @@ -342,7 +360,7 @@ namespace osu.Game.Screens.Play private void onCompletion() { // Only show the completion screen if the player hasn't failed - if (ScoreProcessor.HasFailed || completionProgressDelegate != null) + if (HealthProcessor.HasFailed || completionProgressDelegate != null) return; ValidForResume = false; From 04c3a6f8a4c58672cca7b98085548e00197554ce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Dec 2019 20:18:17 +0900 Subject: [PATCH 32/86] Move more properties to the base class --- .../Rulesets/Scoring/JudgementProcessor.cs | 20 ++++++++++++++++++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 21 ------------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs index 854b926846..c7ac466eb0 100644 --- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs +++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs @@ -11,6 +11,16 @@ namespace osu.Game.Rulesets.Scoring { public abstract class JudgementProcessor { + /// + /// Invoked when all s have been judged by this . + /// + public event Action AllJudged; + + /// + /// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by this . + /// + public event Action NewJudgement; + /// /// The maximum number of hits that can be judged. /// @@ -21,6 +31,11 @@ namespace osu.Game.Rulesets.Scoring /// public int JudgedHits { get; private set; } + /// + /// Whether all s have been processed. + /// + public bool HasCompleted => JudgedHits == MaxHits; + protected JudgementProcessor(IBeatmap beatmap) { ApplyBeatmap(beatmap); @@ -47,6 +62,11 @@ namespace osu.Game.Rulesets.Scoring JudgedHits++; ApplyResultInternal(result); + + NewJudgement?.Invoke(result); + + if (HasCompleted) + AllJudged?.Invoke(); } /// diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 945c21e196..093ba16e57 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -10,7 +10,6 @@ using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Scoring; namespace osu.Game.Rulesets.Scoring @@ -21,16 +20,6 @@ namespace osu.Game.Rulesets.Scoring private const double combo_portion = 0.7; private const double max_score = 1000000; - /// - /// Invoked when all s have been judged. - /// - public event Action AllJudged; - - /// - /// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the . - /// - public event Action NewJudgement; - /// /// The current total score. /// @@ -66,11 +55,6 @@ namespace osu.Game.Rulesets.Scoring /// public readonly Bindable Mode = new Bindable(); - /// - /// Whether all s have been processed. - /// - public bool HasCompleted => JudgedHits == MaxHits; - private double maxHighestCombo; private double maxBaseScore; @@ -158,11 +142,6 @@ namespace osu.Game.Rulesets.Scoring } updateScore(); - - NewJudgement?.Invoke(result); - - if (HasCompleted) - AllJudged?.Invoke(); } protected sealed override void RevertResultInternal(JudgementResult result) From 50fa6c5f77284fe61805f7bd04f473e5f93558d4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Dec 2019 20:18:23 +0900 Subject: [PATCH 33/86] Update score on reverts --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 093ba16e57..acd394d955 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -165,6 +165,8 @@ namespace osu.Game.Rulesets.Scoring baseScore -= result.Judgement.NumericResultFor(result); rollingMaxBaseScore -= result.Judgement.MaxNumericResult; } + + updateScore(); } private void updateScore() From 822903d5db8476bcc7c38629b03c21ea8ea0bd30 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Dec 2019 18:00:04 +0900 Subject: [PATCH 34/86] Update song select statistics when mod changes settings --- osu.Game/Overlays/Settings/ISettingsItem.cs | 13 +++++++ osu.Game/Overlays/Settings/SettingsItem.cs | 16 +++++---- .../Screens/Select/Details/AdvancedStats.cs | 36 ++++++++++++++++++- 3 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Overlays/Settings/ISettingsItem.cs diff --git a/osu.Game/Overlays/Settings/ISettingsItem.cs b/osu.Game/Overlays/Settings/ISettingsItem.cs new file mode 100644 index 0000000000..e7afa48502 --- /dev/null +++ b/osu.Game/Overlays/Settings/ISettingsItem.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics; + +namespace osu.Game.Overlays.Settings +{ + public interface ISettingsItem : IDrawable, IDisposable + { + event Action SettingChanged; + } +} diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 31fcb7abd8..35f28ab1b2 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -20,7 +21,7 @@ using osuTK; namespace osu.Game.Overlays.Settings { - public abstract class SettingsItem : Container, IFilterable + public abstract class SettingsItem : Container, IFilterable, ISettingsItem { protected abstract Drawable CreateControl(); @@ -34,8 +35,6 @@ namespace osu.Game.Overlays.Settings private SpriteText text; - private readonly RestoreDefaultValueButton restoreDefaultButton; - public bool ShowsDefaultIndicator = true; public virtual string LabelText @@ -70,8 +69,12 @@ namespace osu.Game.Overlays.Settings public bool FilteringActive { get; set; } + public event Action SettingChanged; + protected SettingsItem() { + RestoreDefaultValueButton restoreDefaultButton; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; @@ -87,13 +90,12 @@ namespace osu.Game.Overlays.Settings Child = Control = CreateControl() }, }; - } - [BackgroundDependencyLoader] - private void load() - { + // all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is + // never loaded, but requires bindable storage. if (controlWithCurrent != null) { + controlWithCurrent.Current.ValueChanged += _ => SettingChanged?.Invoke(); controlWithCurrent.Current.DisabledChanged += disabled => { Colour = disabled ? Color4.Gray : Color4.White; }; if (ShowsDefaultIndicator) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 9c9c33274f..ad2b5885d7 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -16,6 +16,10 @@ using osu.Framework.Bindables; using System.Collections.Generic; using osu.Game.Rulesets.Mods; using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Threading; +using osu.Game.Configuration; +using osu.Game.Overlays.Settings; namespace osu.Game.Screens.Select.Details { @@ -69,7 +73,37 @@ namespace osu.Game.Screens.Select.Details { base.LoadComplete(); - mods.BindValueChanged(_ => updateStatistics(), true); + mods.BindValueChanged(modsChanged, true); + } + + private readonly List references = new List(); + + private void modsChanged(ValueChangedEvent> mods) + { + // TODO: find a more permanent solution for this if/when it is needed in other components. + // this is generating drawables for the only purpose of storing bindable references. + foreach (var r in references) + r.Dispose(); + + references.Clear(); + + ScheduledDelegate debounce = null; + + foreach (var mod in mods.NewValue.OfType()) + { + foreach (var setting in mod.CreateSettingsControls().OfType()) + { + setting.SettingChanged += () => + { + debounce?.Cancel(); + debounce = Scheduler.AddDelayed(updateStatistics, 100); + }; + + references.Add(setting); + } + } + + updateStatistics(); } private void updateStatistics() From a6bdf04f6b6372fc7e6fb4f62d7dcb27e761c6f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Dec 2019 18:36:39 +0900 Subject: [PATCH 35/86] Remove unused using --- osu.Game/Screens/Select/Details/AdvancedStats.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index ad2b5885d7..a147527f6c 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -16,7 +16,6 @@ using osu.Framework.Bindables; using System.Collections.Generic; using osu.Game.Rulesets.Mods; using System.Linq; -using System.Threading.Tasks; using osu.Framework.Threading; using osu.Game.Configuration; using osu.Game.Overlays.Settings; From 08b477ed5248211d9f501258b33b906a8efa7c7b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 20 Dec 2019 18:30:23 +0800 Subject: [PATCH 36/86] make ModDifficultyAdjust abstract --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../Mods/CatchModDifficultyAdjust.cs | 52 ++++++++++++++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Mods/ManiaModDifficultyAdjust.cs | 32 +++++++++ .../Mods/OsuModDifficultyAdjust.cs | 52 ++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- .../Mods/TaikoModDifficultyAdjust.cs | 32 +++++++++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 67 ++++++------------- 9 files changed, 193 insertions(+), 50 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs create mode 100644 osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs create mode 100644 osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 8f946343a7..4228b86795 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -109,7 +109,7 @@ namespace osu.Game.Rulesets.Catch case ModType.Conversion: return new Mod[] { - new ModDifficultyAdjust(), + new CatchModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs new file mode 100644 index 0000000000..127b6c1c0b --- /dev/null +++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Catch.Mods +{ + public class CatchModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Drain Rate", "Override a beatmap's set HP.")] + public override BindableNumber DrainRate { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Fruit Size", "Override a beatmap's set CS.")] + public override BindableNumber CircleSize { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Approach Rate", "Override a beatmap's set AR.")] + public override BindableNumber ApproachRate { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] + public override BindableNumber OverallDifficulty { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + } +} diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index ea64dfaffa..9ab588c550 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -151,7 +151,7 @@ namespace osu.Game.Rulesets.Mania new ManiaModRandom(), new ManiaModDualStages(), new ManiaModMirror(), - new ModDifficultyAdjust(), + new ManiaModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs new file mode 100644 index 0000000000..fd1315523c --- /dev/null +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Mania.Mods +{ + public class ManiaModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Drain Rate", "Override a beatmap's set HP.")] + public override BindableNumber DrainRate { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] + public override BindableNumber OverallDifficulty { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs new file mode 100644 index 0000000000..3531e002b8 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Drain Rate", "Override a beatmap's set HP.")] + public override BindableNumber DrainRate { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Circle Size", "Override a beatmap's set CS.")] + public override BindableNumber CircleSize { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Approach Rate", "Override a beatmap's set AR.")] + public override BindableNumber ApproachRate { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] + public override BindableNumber OverallDifficulty { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index d097235839..a42402151f 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Osu return new Mod[] { new OsuModTarget(), - new ModDifficultyAdjust(), + new OsuModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs new file mode 100644 index 0000000000..b7007eedcd --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Taiko.Mods +{ + public class TaikoModDifficultyAdjust : ModDifficultyAdjust + { + [SettingSource("Drain Rate", "Override a beatmap's set HP.")] + public override BindableNumber DrainRate { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + + [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] + public override BindableNumber OverallDifficulty { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; + } +} diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 29b74fc4e0..a055c29efe 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko case ModType.Conversion: return new Mod[] { - new ModDifficultyAdjust(), + new TaikoModDifficultyAdjust(), }; case ModType.Automation: diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index b23297345b..625749903a 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -5,11 +5,10 @@ using osu.Game.Beatmaps; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using System; -using osu.Game.Configuration; namespace osu.Game.Rulesets.Mods { - public class ModDifficultyAdjust : Mod, IApplicableToDifficulty + public abstract class ModDifficultyAdjust : Mod, IApplicableToDifficulty { public override string Name => @"Difficulty Adjust"; @@ -25,45 +24,13 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModHardRock) }; - [SettingSource("Drain Rate", "Override the beatmap's set HP")] - public BindableNumber DrainRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; + public virtual BindableNumber DrainRate { get; } - [SettingSource("Circle Size", "Override the beatmap's set CS")] - public BindableNumber CircleSize { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; + public virtual BindableNumber CircleSize { get; } - [SettingSource("Approach Rate", "Override the beatmap's set AR")] - public BindableNumber ApproachRate { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; + public virtual BindableNumber ApproachRate { get; } - [SettingSource("Overall Difficulty", "Override the beatmap's set OD")] - public BindableNumber OverallDifficulty { get; } = new BindableFloat - { - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - Precision = 0.1F, - }; + public virtual BindableNumber OverallDifficulty { get; } private BeatmapDifficulty difficulty; @@ -72,17 +39,25 @@ namespace osu.Game.Rulesets.Mods if (this.difficulty == null || this.difficulty.ID != difficulty.ID) { this.difficulty = difficulty; - DrainRate.Value = DrainRate.Default = difficulty.DrainRate; - CircleSize.Value = CircleSize.Default = difficulty.CircleSize; - ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; - OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; + + if (DrainRate != null) + DrainRate.Value = DrainRate.Default = difficulty.DrainRate; + + if (CircleSize != null) + CircleSize.Value = CircleSize.Default = difficulty.CircleSize; + + if (ApproachRate != null) + ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; + + if (OverallDifficulty != null) + OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; } else { - difficulty.DrainRate = DrainRate.Value; - difficulty.CircleSize = CircleSize.Value; - difficulty.ApproachRate = ApproachRate.Value; - difficulty.OverallDifficulty = OverallDifficulty.Value; + difficulty.DrainRate = DrainRate?.Value ?? difficulty.DrainRate; + difficulty.CircleSize = CircleSize?.Value ?? difficulty.CircleSize; + difficulty.ApproachRate = ApproachRate?.Value ?? difficulty.ApproachRate; + difficulty.OverallDifficulty = OverallDifficulty?.Value ?? difficulty.OverallDifficulty; } } } From 1bd44529dd31302a62a55d424135c316233d5384 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 20 Dec 2019 18:31:16 +0800 Subject: [PATCH 37/86] add full-stop to mod description for consistency --- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 625749903a..546533709e 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => @"Difficulty Adjust"; - public override string Description => @"Override a beatmap's difficulty settings"; + public override string Description => @"Override a beatmap's difficulty settings."; public override string Acronym => "DA"; From 0eef21894561c17718fc641d94db16a193fabd03 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 20 Dec 2019 18:42:29 +0800 Subject: [PATCH 38/86] add missing new line --- osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index 3531e002b8..4847ddc3c4 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -49,4 +49,4 @@ namespace osu.Game.Rulesets.Osu.Mods Value = 5, }; } -} \ No newline at end of file +} From df14f473c25f023b8b5cc25c0dca8a9042a89f05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Dec 2019 19:00:37 +0900 Subject: [PATCH 39/86] Split tests out --- .../SongSelect/TestSceneBeatmapDetailArea.cs | 156 ++++++++---------- 1 file changed, 66 insertions(+), 90 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs index 66144cbfe4..de4e77fe70 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs @@ -25,57 +25,43 @@ namespace osu.Game.Tests.Visual.SongSelect private ModDisplay modDisplay; + private BeatmapDetailArea detailsArea; + + [Resolved] + private RulesetStore rulesets { get; set; } + [BackgroundDependencyLoader] private void load(OsuGameBase game, RulesetStore rulesets) { - BeatmapDetailArea detailsArea; - Add(detailsArea = new BeatmapDetailArea - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(550f, 450f), - }); + } - Add(modDisplay = new ModDisplay + [SetUp] + public void SetUp() => Schedule(() => + { + Children = new Drawable[] { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Position = new Vector2(0, 25), - }); + detailsArea = new BeatmapDetailArea + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(550f, 450f), + }, + modDisplay = new ModDisplay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Position = new Vector2(0, 25), + } + }; modDisplay.Current.BindTo(SelectedMods); + }); - AddStep("all metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - BeatmapSet = new BeatmapSetInfo - { - Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } - }, - Version = "All Metrics", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has all the metrics", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - }, - StarDifficulty = 5.3f, - Metrics = new BeatmapMetrics - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - } - })); - + [Test] + public void TestBasicScenarios() + { + showAllMetrics(); AddStep("all except source", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap { BeatmapInfo = @@ -178,60 +164,50 @@ namespace osu.Game.Tests.Visual.SongSelect })); AddStep("null beatmap", () => detailsArea.Beatmap = null); + } + + [Test] + public void TestModAdjustments() + { + showAllMetrics(); Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance(); - AddStep("with EZ mod", () => + AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) }); + AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) }); + } + + private void showAllMetrics() + { + AddStep("all metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap { - detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap + BeatmapInfo = { - BeatmapInfo = + BeatmapSet = new BeatmapSetInfo { - Version = "Has Easy Mod", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has the easy mod enabled", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 3, - DrainRate = 3, - OverallDifficulty = 3, - ApproachRate = 3, - }, - StarDifficulty = 1f, - } - }); - - SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) }; - }); - - AddStep("with HR mod", () => - { - detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } + }, + Version = "All Metrics", + Metadata = new BeatmapMetadata { - Version = "Has Hard Rock Mod", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has the hard rock mod enabled", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 3, - DrainRate = 3, - OverallDifficulty = 3, - ApproachRate = 3, - }, - StarDifficulty = 1f, - } - }); - - SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) }; - }); + Source = "osu!lazer", + Tags = "this beatmap has all the metrics", + }, + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 7, + DrainRate = 1, + OverallDifficulty = 5.7f, + ApproachRate = 3.5f, + }, + StarDifficulty = 5.3f, + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), + }, + } + })); } } } From 8d0dd1497b291898dc216754a7561e1c61e3b73c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 21 Dec 2019 12:26:58 +0300 Subject: [PATCH 40/86] Add legacy beatmap skin test scene with combo colours tests --- .../TestSceneLegacyBeatmapSkin.cs | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs new file mode 100644 index 0000000000..8ad66d833f --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -0,0 +1,173 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens; +using osu.Game.Screens.Play; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneLegacyBeatmapSkin : OsuTestScene + { + [Resolved] + private AudioManager audio { get; set; } + + [Test] + public void TestBeatmapComboColours() + { + ExposedPlayer player = null; + ISkin gameplaySkin = null; + IReadOnlyList colours = null; + + AddStep("load beatmap", () => player = loadBeatmap(false, true)); + AddUntilStep("wait for player", () => player.IsLoaded); + AddStep("attach skin requester", () => gameplaySkin = addSkinRequester(player)); + + AddStep("retrieve combo colours", () => colours = gameplaySkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); + AddAssert("is beatmap colours", () => colours.SequenceEqual(TestBeatmapSkin.Colours)); + } + + [Test] + public void TestEmptyBeatmapComboColours() + { + ExposedPlayer player = null; + ISkin gameplaySkin = null; + IReadOnlyList colours = null; + + AddStep("load no-colour beatmap", () => player = loadBeatmap(false, false)); + AddUntilStep("wait for player", () => player.IsLoaded); + AddStep("attach skin requester", () => gameplaySkin = addSkinRequester(player)); + + AddStep("retrieve combo colours", () => colours = gameplaySkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); + AddAssert("is default skin colours", () => colours.SequenceEqual(SkinConfiguration.DefaultComboColours)); + } + + [Test] + public void TestEmptyBeatmapCustomSkinColours() + { + ExposedPlayer player = null; + ISkin gameplaySkin = null; + IReadOnlyList colours = null; + + AddStep("load no-colour beatmap", () => player = loadBeatmap(true, false)); + AddUntilStep("wait for player", () => player.IsLoaded); + AddStep("attach skin requester", () => gameplaySkin = addSkinRequester(player)); + + AddStep("retrieve combo colours", () => colours = gameplaySkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); + AddAssert("is custom skin colours", () => colours.SequenceEqual(TestSkin.Colours)); + } + + private ExposedPlayer loadBeatmap(bool skinHasCustomColours, bool beatmapHasCustomColours) + { + ExposedPlayer player; + + Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasCustomColours); + Child = new SkinProvidingContainer(new TestSkin(skinHasCustomColours)) + .WithChild(new OsuScreenStack(player = new ExposedPlayer()) { RelativeSizeAxes = Axes.Both }); + + return player; + } + + private ISkin addSkinRequester(ExposedPlayer player) + { + SkinRequester skin; + player.BeatmapSkinContainer.Add(skin = new SkinRequester()); + return skin; + } + + private class SkinRequester : Component, ISkin + { + [Resolved] + private ISkinSource skin { get; set; } + + public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component); + + public Texture GetTexture(string componentName) => skin.GetTexture(componentName); + + public SampleChannel GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo); + + public IBindable GetConfig(TLookup lookup) => skin.GetConfig(lookup); + } + + private class ExposedPlayer : Player + { + public ExposedPlayer() + : base(false, false) + { + } + + public BeatmapSkinProvidingContainer BeatmapSkinContainer => GameplayClockContainer.OfType().First().OfType().First(); + } + + private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap + { + private readonly bool hasColours; + + public CustomSkinWorkingBeatmap(AudioManager audio, bool hasColours) + : base(new Beatmap + { + BeatmapInfo = + { + BeatmapSet = new BeatmapSetInfo(), + Ruleset = new OsuRuleset().RulesetInfo, + }, + HitObjects = { new HitCircle { Position = new Vector2(256, 192) } } + }, null, null, audio) + { + this.hasColours = hasColours; + } + + protected override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, hasColours); + } + + private class TestBeatmapSkin : LegacyBeatmapSkin + { + public static Color4[] Colours { get; } = + { + new Color4(50, 100, 150, 255), + new Color4(40, 80, 120, 255), + }; + + public TestBeatmapSkin(BeatmapInfo beatmap, bool hasColours) + : base(beatmap, new ResourceStore(), null) + { + if (hasColours) + Configuration.AddComboColours(Colours); + } + } + + private class TestSkin : LegacySkin + { + public static Color4[] Colours { get; } = + { + new Color4(10, 100, 150, 255), + new Color4(20, 20, 20, 255), + }; + + public TestSkin(bool hasCustomColours) + : base(new SkinInfo(), null, null, string.Empty) + { + if (hasCustomColours) + Configuration.AddComboColours(Colours); + } + } + } +} From ff5e6c0dcfeb8d9eb62ad5527486faa7af24af75 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 21 Dec 2019 12:36:34 +0300 Subject: [PATCH 41/86] Make DefaultComboColours a property --- osu.Game/Skinning/SkinConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 3bfc941fd7..e3a0ab23fa 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -20,7 +20,7 @@ namespace osu.Game.Skinning /// internal bool AllowDefaultComboColoursFallback = true; - public static List DefaultComboColours = new List + public static List DefaultComboColours { get; } = new List { new Color4(255, 192, 0, 255), new Color4(0, 202, 0, 255), From a6632cf1ef9708faeacbb35c61e812fc2a8bcc83 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 21 Dec 2019 12:53:05 +0300 Subject: [PATCH 42/86] Remove unnecessary skin requester and user-skin providing container --- .../TestSceneLegacyBeatmapSkin.cs | 74 ++++++++----------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index 8ad66d833f..c26afefc41 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -1,18 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; -using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; @@ -34,87 +30,69 @@ namespace osu.Game.Rulesets.Osu.Tests public void TestBeatmapComboColours() { ExposedPlayer player = null; - ISkin gameplaySkin = null; IReadOnlyList colours = null; AddStep("load beatmap", () => player = loadBeatmap(false, true)); AddUntilStep("wait for player", () => player.IsLoaded); - AddStep("attach skin requester", () => gameplaySkin = addSkinRequester(player)); - AddStep("retrieve combo colours", () => colours = gameplaySkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); - AddAssert("is beatmap colours", () => colours.SequenceEqual(TestBeatmapSkin.Colours)); + AddStep("retrieve combo colours", () => colours = player.BeatmapSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); + AddAssert("is beatmap skin colours", () => colours.SequenceEqual(TestBeatmapSkin.Colours)); } [Test] public void TestEmptyBeatmapComboColours() { ExposedPlayer player = null; - ISkin gameplaySkin = null; IReadOnlyList colours = null; AddStep("load no-colour beatmap", () => player = loadBeatmap(false, false)); AddUntilStep("wait for player", () => player.IsLoaded); - AddStep("attach skin requester", () => gameplaySkin = addSkinRequester(player)); - AddStep("retrieve combo colours", () => colours = gameplaySkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); - AddAssert("is default skin colours", () => colours.SequenceEqual(SkinConfiguration.DefaultComboColours)); + AddStep("retrieve combo colours", () => colours = player.BeatmapSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); + AddAssert("is default user skin colours", () => colours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } [Test] public void TestEmptyBeatmapCustomSkinColours() { ExposedPlayer player = null; - ISkin gameplaySkin = null; IReadOnlyList colours = null; AddStep("load no-colour beatmap", () => player = loadBeatmap(true, false)); AddUntilStep("wait for player", () => player.IsLoaded); - AddStep("attach skin requester", () => gameplaySkin = addSkinRequester(player)); - AddStep("retrieve combo colours", () => colours = gameplaySkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); - AddAssert("is custom skin colours", () => colours.SequenceEqual(TestSkin.Colours)); + AddStep("retrieve combo colours", () => colours = player.BeatmapSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); + AddAssert("is custom user skin colours", () => colours.SequenceEqual(TestSkin.Colours)); } - private ExposedPlayer loadBeatmap(bool skinHasCustomColours, bool beatmapHasCustomColours) + private ExposedPlayer loadBeatmap(bool userHasCustomColours, bool beatmapHasColours) { ExposedPlayer player; - Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasCustomColours); - Child = new SkinProvidingContainer(new TestSkin(skinHasCustomColours)) - .WithChild(new OsuScreenStack(player = new ExposedPlayer()) { RelativeSizeAxes = Axes.Both }); + Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasColours); + Child = new OsuScreenStack(player = new ExposedPlayer(userHasCustomColours)) { RelativeSizeAxes = Axes.Both }; return player; } - private ISkin addSkinRequester(ExposedPlayer player) - { - SkinRequester skin; - player.BeatmapSkinContainer.Add(skin = new SkinRequester()); - return skin; - } - - private class SkinRequester : Component, ISkin - { - [Resolved] - private ISkinSource skin { get; set; } - - public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component); - - public Texture GetTexture(string componentName) => skin.GetTexture(componentName); - - public SampleChannel GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo); - - public IBindable GetConfig(TLookup lookup) => skin.GetConfig(lookup); - } - private class ExposedPlayer : Player { - public ExposedPlayer() + private readonly bool userHasCustomColours; + + public ExposedPlayer(bool userHasCustomColours) : base(false, false) { + this.userHasCustomColours = userHasCustomColours; } - public BeatmapSkinProvidingContainer BeatmapSkinContainer => GameplayClockContainer.OfType().First().OfType().First(); + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + dependencies.CacheAs(new TestSkin(userHasCustomColours)); + return dependencies; + } + + public BeatmapSkinProvidingContainer BeatmapSkin => GameplayClockContainer.OfType().First().OfType().First(); } private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap @@ -154,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Tests } } - private class TestSkin : LegacySkin + private class TestSkin : LegacySkin, ISkinSource { public static Color4[] Colours { get; } = { @@ -168,6 +146,12 @@ namespace osu.Game.Rulesets.Osu.Tests if (hasCustomColours) Configuration.AddComboColours(Colours); } + + public event Action SourceChanged + { + add { } + remove { } + } } } } From 13425568945c4bde5c130266b2ff19156f867fef Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 15 Dec 2019 08:34:57 -0800 Subject: [PATCH 43/86] Allow ctrl tabbing navigation to chat and song select leaderboards --- osu.Game/Overlays/ChatOverlay.cs | 1 + osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 33bcc4c139..08043a097b 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -171,6 +171,7 @@ namespace osu.Game.Overlays d.Origin = Anchor.BottomLeft; d.RelativeSizeAxes = Axes.Both; d.OnRequestLeave = channelManager.LeaveChannel; + d.Tabbable = true; }), } }, diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index 433e8ee398..a6933b478e 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -48,6 +48,7 @@ namespace osu.Game.Screens.Select Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, + Tabbable = true, }, }, modsCheckbox = new OsuTabControlCheckbox From 119b48ccb0e77e8ed35c3e2537b2dc1fb51b4d2d Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 15 Dec 2019 08:35:38 -0800 Subject: [PATCH 44/86] Remove redundant tab item override --- osu.Game/Graphics/UserInterface/BreadcrumbControl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index d1e55fee24..93ea6bbbe6 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs @@ -52,7 +52,6 @@ namespace osu.Game.Graphics.UserInterface public override bool HandleNonPositionalInput => State == Visibility.Visible; public override bool HandlePositionalInput => State == Visibility.Visible; - public override bool IsRemovable => true; private Visibility state; From 725008286f1cd5861fef48d5acbc5ca11e505496 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Dec 2019 06:09:16 +0900 Subject: [PATCH 45/86] Move test and remove pointless duplicate tests --- .../SongSelect/TestSceneBeatmapDetailArea.cs | 213 ------------------ .../SongSelect/TestSceneBeatmapDetails.cs | 15 ++ 2 files changed, 15 insertions(+), 213 deletions(-) delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs deleted file mode 100644 index de4e77fe70..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select; -using osu.Game.Tests.Beatmaps; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - [System.ComponentModel.Description("PlaySongSelect leaderboard/details area")] - public class TestSceneBeatmapDetailArea : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] { typeof(BeatmapDetails) }; - - private ModDisplay modDisplay; - - private BeatmapDetailArea detailsArea; - - [Resolved] - private RulesetStore rulesets { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuGameBase game, RulesetStore rulesets) - { - } - - [SetUp] - public void SetUp() => Schedule(() => - { - Children = new Drawable[] - { - detailsArea = new BeatmapDetailArea - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(550f, 450f), - }, - modDisplay = new ModDisplay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Position = new Vector2(0, 25), - } - }; - - modDisplay.Current.BindTo(SelectedMods); - }); - - [Test] - public void TestBasicScenarios() - { - showAllMetrics(); - AddStep("all except source", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - BeatmapSet = new BeatmapSetInfo - { - Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } - }, - Version = "All Metrics", - Metadata = new BeatmapMetadata - { - Tags = "this beatmap has all the metrics", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - }, - StarDifficulty = 5.3f, - Metrics = new BeatmapMetrics - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - } - })); - - AddStep("ratings", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - BeatmapSet = new BeatmapSetInfo - { - Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } - }, - Version = "Only Ratings", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has ratings metrics but not retries or fails", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 6, - DrainRate = 9, - OverallDifficulty = 6, - ApproachRate = 6, - }, - StarDifficulty = 4.8f - } - })); - - AddStep("fails+retries", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Version = "Only Retries and Fails", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has retries and fails but no ratings", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 3.7f, - DrainRate = 6, - OverallDifficulty = 6, - ApproachRate = 7, - }, - StarDifficulty = 2.91f, - Metrics = new BeatmapMetrics - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - } - })); - - AddStep("null metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Version = "No Metrics", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has no metrics", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 5, - DrainRate = 5, - OverallDifficulty = 5.5f, - ApproachRate = 6.5f, - }, - StarDifficulty = 1.97f, - } - })); - - AddStep("null beatmap", () => detailsArea.Beatmap = null); - } - - [Test] - public void TestModAdjustments() - { - showAllMetrics(); - - Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance(); - - AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) }); - AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) }); - } - - private void showAllMetrics() - { - AddStep("all metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - BeatmapSet = new BeatmapSetInfo - { - Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } - }, - Version = "All Metrics", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has all the metrics", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - }, - StarDifficulty = 5.3f, - Metrics = new BeatmapMetrics - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - } - })); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs index acf037198f..2521d248e7 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs @@ -3,8 +3,11 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.SongSelect @@ -174,5 +177,17 @@ namespace osu.Game.Tests.Visual.SongSelect OnlineBeatmapID = 162, }); } + + [Resolved] + private RulesetStore rulesets { get; set; } + + [Test] + public void TestModAdjustments() + { + Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance(); + + AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) }); + AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) }); + } } } From 69227d61799a79b6a71249e5769e6a657acea009 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Dec 2019 06:37:18 +0900 Subject: [PATCH 46/86] Add asserts --- .../Visual/SongSelect/TestSceneBeatmapDetails.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs index 2521d248e7..6aa5a76490 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs @@ -5,7 +5,10 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; @@ -181,13 +184,23 @@ namespace osu.Game.Tests.Visual.SongSelect [Resolved] private RulesetStore rulesets { get; set; } + [Resolved] + private OsuColour colours { get; set; } + [Test] public void TestModAdjustments() { + TestAllMetrics(); + Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance(); AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) }); + + AddAssert("first bar coloured blue", () => details.ChildrenOfType().Skip(1).First().AccentColour == colours.BlueDark); + AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) }); + + AddAssert("first bar coloured red", () => details.ChildrenOfType().Skip(1).First().AccentColour == colours.Red); } } } From fe73b9f8d3919a0a983965f5db17569b4f2bd83d Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 22 Dec 2019 16:45:32 +0800 Subject: [PATCH 47/86] make HP and OD generic and instantiate CS and AR to modes that need it --- .../Mods/CatchModDifficultyAdjust.cs | 37 ++++++------ .../Mods/ManiaModDifficultyAdjust.cs | 19 ------ .../Mods/OsuModDifficultyAdjust.cs | 37 ++++++------ .../Mods/TaikoModDifficultyAdjust.cs | 19 ------ osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 59 +++++++++++-------- 5 files changed, 68 insertions(+), 103 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs index 127b6c1c0b..2e1e655844 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -9,18 +10,8 @@ namespace osu.Game.Rulesets.Catch.Mods { public class CatchModDifficultyAdjust : ModDifficultyAdjust { - [SettingSource("Drain Rate", "Override a beatmap's set HP.")] - public override BindableNumber DrainRate { get; } = new BindableFloat() - { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; - [SettingSource("Fruit Size", "Override a beatmap's set CS.")] - public override BindableNumber CircleSize { get; } = new BindableFloat() + public BindableNumber CircleSize { get; } = new BindableFloat() { Precision = 0.1f, MinValue = 1, @@ -30,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.Mods }; [SettingSource("Approach Rate", "Override a beatmap's set AR.")] - public override BindableNumber ApproachRate { get; } = new BindableFloat() + public BindableNumber ApproachRate { get; } = new BindableFloat() { Precision = 0.1f, MinValue = 1, @@ -39,14 +30,20 @@ namespace osu.Game.Rulesets.Catch.Mods Value = 5, }; - [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] - public override BindableNumber OverallDifficulty { get; } = new BindableFloat() + protected override void UpdateSettings(BeatmapDifficulty difficulty) { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; + base.UpdateSettings(difficulty); + + CircleSize.Value = CircleSize.Default = difficulty.CircleSize; + ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; + } + + protected override void ApplySettings(BeatmapDifficulty difficulty) + { + base.ApplySettings(difficulty); + + difficulty.CircleSize = CircleSize.Value; + difficulty.ApproachRate = ApproachRate.Value; + } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs index fd1315523c..5920e0c3b8 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs @@ -9,24 +9,5 @@ namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModDifficultyAdjust : ModDifficultyAdjust { - [SettingSource("Drain Rate", "Override a beatmap's set HP.")] - public override BindableNumber DrainRate { get; } = new BindableFloat() - { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; - - [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] - public override BindableNumber OverallDifficulty { get; } = new BindableFloat() - { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index 4847ddc3c4..3e9c51db85 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -9,18 +10,8 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModDifficultyAdjust : ModDifficultyAdjust { - [SettingSource("Drain Rate", "Override a beatmap's set HP.")] - public override BindableNumber DrainRate { get; } = new BindableFloat() - { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; - [SettingSource("Circle Size", "Override a beatmap's set CS.")] - public override BindableNumber CircleSize { get; } = new BindableFloat() + public BindableNumber CircleSize { get; } = new BindableFloat() { Precision = 0.1f, MinValue = 1, @@ -30,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods }; [SettingSource("Approach Rate", "Override a beatmap's set AR.")] - public override BindableNumber ApproachRate { get; } = new BindableFloat() + public BindableNumber ApproachRate { get; } = new BindableFloat() { Precision = 0.1f, MinValue = 1, @@ -39,14 +30,20 @@ namespace osu.Game.Rulesets.Osu.Mods Value = 5, }; - [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] - public override BindableNumber OverallDifficulty { get; } = new BindableFloat() + protected override void UpdateSettings(BeatmapDifficulty difficulty) { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; + base.UpdateSettings(difficulty); + + CircleSize.Value = CircleSize.Default = difficulty.CircleSize; + ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; + } + + protected override void ApplySettings(BeatmapDifficulty difficulty) + { + base.ApplySettings(difficulty); + + difficulty.CircleSize = CircleSize.Value; + difficulty.ApproachRate = ApproachRate.Value; + } } } diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs index b7007eedcd..3c4812f922 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs @@ -9,24 +9,5 @@ namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModDifficultyAdjust : ModDifficultyAdjust { - [SettingSource("Drain Rate", "Override a beatmap's set HP.")] - public override BindableNumber DrainRate { get; } = new BindableFloat() - { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; - - [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] - public override BindableNumber OverallDifficulty { get; } = new BindableFloat() - { - Precision = 0.1f, - MinValue = 1, - MaxValue = 10, - Default = 5, - Value = 5, - }; } } diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 546533709e..1405ccec8d 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -5,6 +5,7 @@ using osu.Game.Beatmaps; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using System; +using osu.Game.Configuration; namespace osu.Game.Rulesets.Mods { @@ -24,41 +25,49 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModHardRock) }; - public virtual BindableNumber DrainRate { get; } + [SettingSource("Drain Rate", "Override a beatmap's set HP.")] + public BindableNumber DrainRate { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; - public virtual BindableNumber CircleSize { get; } - - public virtual BindableNumber ApproachRate { get; } - - public virtual BindableNumber OverallDifficulty { get; } + [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] + public BindableNumber OverallDifficulty { get; } = new BindableFloat() + { + Precision = 0.1f, + MinValue = 1, + MaxValue = 10, + Default = 5, + Value = 5, + }; private BeatmapDifficulty difficulty; - public virtual void ApplyToDifficulty(BeatmapDifficulty difficulty) + public void ApplyToDifficulty(BeatmapDifficulty difficulty) { if (this.difficulty == null || this.difficulty.ID != difficulty.ID) { this.difficulty = difficulty; - - if (DrainRate != null) - DrainRate.Value = DrainRate.Default = difficulty.DrainRate; - - if (CircleSize != null) - CircleSize.Value = CircleSize.Default = difficulty.CircleSize; - - if (ApproachRate != null) - ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; - - if (OverallDifficulty != null) - OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; + UpdateSettings(difficulty); } else - { - difficulty.DrainRate = DrainRate?.Value ?? difficulty.DrainRate; - difficulty.CircleSize = CircleSize?.Value ?? difficulty.CircleSize; - difficulty.ApproachRate = ApproachRate?.Value ?? difficulty.ApproachRate; - difficulty.OverallDifficulty = OverallDifficulty?.Value ?? difficulty.OverallDifficulty; - } + ApplySettings(difficulty); + } + + protected virtual void UpdateSettings(BeatmapDifficulty difficulty) + { + DrainRate.Value = DrainRate.Default = difficulty.DrainRate; + OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; + } + + protected virtual void ApplySettings(BeatmapDifficulty difficulty) + { + difficulty.DrainRate = DrainRate.Value; + difficulty.OverallDifficulty = OverallDifficulty.Value; } } } From 00ef2bd8d37c1b226ed39429ca0044723ebb3199 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 22 Dec 2019 16:57:07 +0800 Subject: [PATCH 48/86] remove unused usings --- osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs | 2 -- osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs index 5920e0c3b8..0817f8f9fc 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDifficultyAdjust.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Bindables; -using osu.Game.Configuration; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs index 3c4812f922..56a73ad7df 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModDifficultyAdjust.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Bindables; -using osu.Game.Configuration; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Taiko.Mods From 5d29ff29cbe4464288b299dc2841664d7c970430 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 22 Dec 2019 20:52:00 +0800 Subject: [PATCH 49/86] Animate "Good bye" instead on exit --- osu.Game/Screens/Menu/MainMenu.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 231115d1e1..8437748d9d 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -132,6 +133,8 @@ namespace osu.Game.Screens.Menu private void confirmAndExit() { + if (exitConfirmed) return; + exitConfirmed = true; this.Exit(); } @@ -250,6 +253,12 @@ namespace osu.Game.Screens.Menu return true; } + if (dialogOverlay.CurrentDialog is ConfirmExitDialog) + { + exitConfirmed = true; + dialogOverlay.CurrentDialog.Buttons.First().Click(); + } + buttons.State = ButtonSystemState.Exit; this.FadeOut(3000); return base.OnExiting(next); From 1f41acc5b92648a2d3c51afcf775346cf9090404 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 22 Dec 2019 21:20:55 +0800 Subject: [PATCH 50/86] Integrate auto click into exit confirmed check --- osu.Game/Screens/Menu/MainMenu.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 8437748d9d..ee4d98bd89 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -247,14 +247,14 @@ namespace osu.Game.Screens.Menu public override bool OnExiting(IScreen next) { - if (!exitConfirmed && dialogOverlay != null && !(dialogOverlay.CurrentDialog is ConfirmExitDialog)) + if (!exitConfirmed && dialogOverlay != null) { - dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); - return true; - } + if (!(dialogOverlay.CurrentDialog is ConfirmExitDialog)) + { + dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); + return true; + } - if (dialogOverlay.CurrentDialog is ConfirmExitDialog) - { exitConfirmed = true; dialogOverlay.CurrentDialog.Buttons.First().Click(); } From 796223d3e0e3f62c640a7c4a64046c781b257d87 Mon Sep 17 00:00:00 2001 From: mcendu Date: Sun, 22 Dec 2019 21:39:25 +0800 Subject: [PATCH 51/86] Invert if --- osu.Game/Screens/Menu/MainMenu.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index ee4d98bd89..b28d572b5c 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -249,14 +249,16 @@ namespace osu.Game.Screens.Menu { if (!exitConfirmed && dialogOverlay != null) { - if (!(dialogOverlay.CurrentDialog is ConfirmExitDialog)) + if (dialogOverlay.CurrentDialog is ConfirmExitDialog exitDialog) + { + exitConfirmed = true; + exitDialog.Buttons.First().Click(); + } + else { dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort())); return true; } - - exitConfirmed = true; - dialogOverlay.CurrentDialog.Buttons.First().Click(); } buttons.State = ButtonSystemState.Exit; From e2b4e3580cc55caaa7a0a0941150ab5464d063f8 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 21 Dec 2019 15:48:15 +0100 Subject: [PATCH 52/86] Truncate strings passed to the Discord RPC client to a maximum of 128 bytes --- osu.Desktop/DiscordRichPresence.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index b53ca6161b..45552f1906 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -1,7 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; +using System.Text; using DiscordRPC; +using DiscordRPC.Helper; using DiscordRPC.Message; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -78,8 +81,8 @@ namespace osu.Desktop if (status.Value is UserStatusOnline && activity.Value != null) { - presence.State = activity.Value.Status; - presence.Details = getDetails(activity.Value); + presence.State = truncate(activity.Value.Status); + presence.Details = truncate(getDetails(activity.Value)); } else { @@ -97,6 +100,8 @@ namespace osu.Desktop client.SetPresence(presence); } + private string truncate(string str) => str.WithinLength(128) ? str : new string (str.TakeWhile((c, i) => Encoding.UTF8.GetByteCount(str.Substring(0, i + 1)) <= 125).ToArray()) + '…'; //the ellipsis char is 3 bytes long in UTF8 + private string getDetails(UserActivity activity) { switch (activity) From b038c192d12df09206f072214c2e20959dd4fe09 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 22 Dec 2019 19:47:47 -0800 Subject: [PATCH 53/86] Rename property to IsSwitchable --- osu.Game/Overlays/ChatOverlay.cs | 2 +- osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 08043a097b..e80c51d82a 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -171,7 +171,7 @@ namespace osu.Game.Overlays d.Origin = Anchor.BottomLeft; d.RelativeSizeAxes = Axes.Both; d.OnRequestLeave = channelManager.LeaveChannel; - d.Tabbable = true; + d.IsSwitchable = true; }), } }, diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index a6933b478e..19ecdb6dbf 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Select Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, - Tabbable = true, + IsSwitchable = true, }, }, modsCheckbox = new OsuTabControlCheckbox From 125f4286ae75fec93c83a50c243536782a898aed Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 23 Dec 2019 10:55:44 +0100 Subject: [PATCH 54/86] Move truncate() to a method body --- osu.Desktop/DiscordRichPresence.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 45552f1906..cd5fba533b 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -100,7 +100,13 @@ namespace osu.Desktop client.SetPresence(presence); } - private string truncate(string str) => str.WithinLength(128) ? str : new string (str.TakeWhile((c, i) => Encoding.UTF8.GetByteCount(str.Substring(0, i + 1)) <= 125).ToArray()) + '…'; //the ellipsis char is 3 bytes long in UTF8 + private string truncate(string str) + { + if (str.WithinLength(128)) + return str; + + return new string(str.TakeWhile((c, i) => Encoding.UTF8.GetByteCount(str.Substring(0, i + 1)) <= 125).ToArray()) + '…'; //the ellipsis char is 3 bytes long in UTF8 + } private string getDetails(UserActivity activity) { From c766477abc64c192f458d8aca45edb7fe47e40db Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 23 Dec 2019 19:08:16 +0900 Subject: [PATCH 55/86] Fix testcase containing bad hitobject --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index 02ce77e707..bd9d948782 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Tests EndTime = 6000, }, // placeholder object to avoid hitting the results screen - new HitObject + new HitCircle { StartTime = 99999, } From c7936e40d5c2b02a37ef7821b5d9698146e68a88 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 23 Dec 2019 19:13:36 +0900 Subject: [PATCH 56/86] Protect against potential nullref --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5dfdeb5ebc..8970f9ac88 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -562,7 +562,7 @@ namespace osu.Game.Screens.Play // GameplayClockContainer performs seeks / start / stop operations on the beatmap's track. // as we are no longer the current screen, we cannot guarantee the track is still usable. - GameplayClockContainer.StopUsingBeatmapClock(); + GameplayClockContainer?.StopUsingBeatmapClock(); fadeOut(); return base.OnExiting(next); From 43024122430816e425d69174bf554edfd2be4930 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 23 Dec 2019 19:34:12 +0900 Subject: [PATCH 57/86] Simplify implementation --- osu.Desktop/DiscordRichPresence.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index cd5fba533b..85e4b8db55 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -1,10 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; +using System; using System.Text; using DiscordRPC; -using DiscordRPC.Helper; using DiscordRPC.Message; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -100,12 +99,19 @@ namespace osu.Desktop client.SetPresence(presence); } - private string truncate(string str) + private string truncate(ReadOnlySpan str) { - if (str.WithinLength(128)) - return str; + if (Encoding.UTF8.GetByteCount(str) < 128) + return new string(str); - return new string(str.TakeWhile((c, i) => Encoding.UTF8.GetByteCount(str.Substring(0, i + 1)) <= 125).ToArray()) + '…'; //the ellipsis char is 3 bytes long in UTF8 + int ellipsisLength = Encoding.UTF8.GetByteCount(new[] { '…' }); + + do + { + str = str[..^1]; + } while (Encoding.UTF8.GetByteCount(str) + ellipsisLength > 128); + + return new string(str) + '…'; } private string getDetails(UserActivity activity) From b9bc1c954eae7513a1fbb31e90cc71ed43c2aabd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Dec 2019 19:50:35 +0900 Subject: [PATCH 58/86] Disable automatic retry of failed discord RPC connections --- osu.Desktop/DiscordRichPresence.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 8818cef8eb..71b73ec78e 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -43,6 +43,10 @@ namespace osu.Desktop }; client.OnReady += onReady; + + // safety measure for now, until we performance test / improve backoff for failed connections. + client.OnConnectionFailed += (_, __) => client.Deinitialize(); + client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network); (user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u => From f1f9e1f658cca54a0888629a6cd9e5c761fe3115 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 23 Dec 2019 19:56:05 +0900 Subject: [PATCH 59/86] Don't truncate with exactly 128 bytes --- osu.Desktop/DiscordRichPresence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 9d2fad2e1a..ce878edda8 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -100,7 +100,7 @@ namespace osu.Desktop private string truncate(ReadOnlySpan str) { - if (Encoding.UTF8.GetByteCount(str) < 128) + if (Encoding.UTF8.GetByteCount(str) <= 128) return new string(str); int ellipsisLength = Encoding.UTF8.GetByteCount(new[] { '…' }); From a324bfbc2c6960016362c647458f1dfaf536a8c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Dec 2019 13:48:27 +0900 Subject: [PATCH 60/86] Remove LegacyID from Ruleset --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 4 ++-- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 4 ++-- osu.Game.Rulesets.Osu/OsuRuleset.cs | 4 ++-- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 4 ++-- osu.Game/Rulesets/ILegacyRuleset.cs | 13 +++++++++++++ osu.Game/Rulesets/Ruleset.cs | 8 +------- osu.Game/Rulesets/RulesetStore.cs | 11 ++++++++--- 7 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 osu.Game/Rulesets/ILegacyRuleset.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index b8a844cb86..063294f836 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -24,7 +24,7 @@ using System; namespace osu.Game.Rulesets.Catch { - public class CatchRuleset : Ruleset + public class CatchRuleset : Ruleset, ILegacyRuleset { public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableCatchRuleset(this, beatmap, mods); @@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Catch public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score); - public override int? LegacyID => 2; + public int LegacyID => 2; public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame(); } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index bf630cf892..dc2485bfb0 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -31,7 +31,7 @@ using osu.Game.Scoring; namespace osu.Game.Rulesets.Mania { - public class ManiaRuleset : Ruleset + public class ManiaRuleset : Ruleset, ILegacyRuleset { public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableManiaRuleset(this, beatmap, mods); @@ -178,7 +178,7 @@ namespace osu.Game.Rulesets.Mania public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(this, beatmap); - public override int? LegacyID => 3; + public int LegacyID => 3; public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 27af615935..cab1980dde 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -32,7 +32,7 @@ using System; namespace osu.Game.Rulesets.Osu { - public class OsuRuleset : Ruleset + public class OsuRuleset : Ruleset, ILegacyRuleset { public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableOsuRuleset(this, beatmap, mods); @@ -178,7 +178,7 @@ namespace osu.Game.Rulesets.Osu public override ISkin CreateLegacySkinProvider(ISkinSource source) => new OsuLegacySkinTransformer(source); - public override int? LegacyID => 0; + public int LegacyID => 0; public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index ca7ab30867..a4cfce0dcc 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -24,7 +24,7 @@ using System; namespace osu.Game.Rulesets.Taiko { - public class TaikoRuleset : Ruleset + public class TaikoRuleset : Ruleset, ILegacyRuleset { public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableTaikoRuleset(this, beatmap, mods); @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Taiko public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new TaikoPerformanceCalculator(this, beatmap, score); - public override int? LegacyID => 1; + public int LegacyID => 1; public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); } diff --git a/osu.Game/Rulesets/ILegacyRuleset.cs b/osu.Game/Rulesets/ILegacyRuleset.cs new file mode 100644 index 0000000000..06a85b5261 --- /dev/null +++ b/osu.Game/Rulesets/ILegacyRuleset.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets +{ + public interface ILegacyRuleset + { + /// + /// Identifies the server-side ID of a legacy ruleset. + /// + int LegacyID { get; } + } +} diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 7ad93379f0..21d96123f1 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets { public abstract class Ruleset { - public readonly RulesetInfo RulesetInfo; + public RulesetInfo RulesetInfo { get; internal set; } public IEnumerable GetAllMods() => Enum.GetValues(typeof(ModType)).Cast() // Confine all mods of each mod type into a single IEnumerable @@ -103,11 +103,6 @@ namespace osu.Game.Rulesets /// The to store the settings. public virtual IRulesetConfigManager CreateConfig(SettingsStore settings) => null; - /// - /// Do not override this unless you are a legacy mode. - /// - public virtual int? LegacyID => null; - /// /// A unique short name to reference this ruleset in online requests. /// @@ -148,7 +143,6 @@ namespace osu.Game.Rulesets Name = Description, ShortName = ShortName, InstantiationInfo = GetType().AssemblyQualifiedName, - ID = LegacyID, Available = true }; } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5d0c5c7ccf..5d2a7df458 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -59,16 +59,21 @@ namespace osu.Game.Rulesets var instances = loadedAssemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r)).ToList(); //add all legacy modes in correct order - foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID)) + foreach (var r in instances.Where(r => r is ILegacyRuleset)) { - if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == r.RulesetInfo.ID) == null) + int legacyId = ((ILegacyRuleset)r).LegacyID; + + if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == legacyId) == null) + { + r.RulesetInfo.ID = legacyId; context.RulesetInfo.Add(r.RulesetInfo); + } } context.SaveChanges(); //add any other modes - foreach (var r in instances.Where(r => r.LegacyID == null)) + foreach (var r in instances.Where(r => !(r is ILegacyRuleset))) { if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null) context.RulesetInfo.Add(r.RulesetInfo); From 0bfd7579362d55a258163c70ba1a8640b1e11eff Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Dec 2019 14:21:16 +0900 Subject: [PATCH 61/86] Make OsuTextBox use BasicTextBox --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 1cac4d76ab..72fa135699 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -12,7 +12,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Graphics.UserInterface { - public class OsuTextBox : TextBox + public class OsuTextBox : BasicTextBox { protected override float LeftRightPadding => 10; @@ -41,6 +41,8 @@ namespace osu.Game.Graphics.UserInterface BackgroundCommit = BorderColour = colour.Yellow; } + protected override Color4 SelectionColour => new Color4(249, 90, 255, 255); + protected override void OnFocus(FocusEvent e) { BorderThickness = 3; From 0677f746aaf2fb7bbf134b7dc1237c04cabbf24d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Dec 2019 16:02:16 +0900 Subject: [PATCH 62/86] Provide the ruleset to converter classes --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs | 4 ++-- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 6 +++--- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs | 2 +- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs | 4 ++-- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs | 6 +++--- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 5 +++-- .../Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs | 6 +++--- osu.Game/Beatmaps/BeatmapConverter.cs | 3 ++- 12 files changed, 23 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index b5497ea89f..036c86ffa3 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -14,8 +14,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps { public class CatchBeatmapConverter : BeatmapConverter { - public CatchBeatmapConverter(IBeatmap beatmap) - : base(beatmap) + public CatchBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) + : base(beatmap, ruleset) { } diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 063294f836..b329f6cd98 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new CatchScoreProcessor(beatmap); - public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap, this); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap); public const string SHORT_NAME = "fruits"; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 6e4491de94..aac3f914a4 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -37,10 +37,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private ManiaBeatmap beatmap; - public ManiaBeatmapConverter(IBeatmap beatmap) - : base(beatmap) + public ManiaBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) + : base(beatmap, ruleset) { - IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo); + IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); var roundedCircleSize = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize); var roundedOverallDifficulty = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index dc2485bfb0..28971b11c5 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mania public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ManiaScoreProcessor(beatmap); - public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score); diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs index 70ba5cd938..877a9ee410 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Replays public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null) { // We don't need to fully convert, just create the converter - var converter = new ManiaBeatmapConverter(beatmap); + var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset()); // NB: Via co-op mod, osu-stable can have two stages with floor(col/2) and ceil(col/2) columns. This will need special handling // elsewhere in the game if we do choose to support the old co-op mod anyway. For now, assume that there is only one stage. diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 2296030f81..7bc14c3e41 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { public class OsuBeatmapConverter : BeatmapConverter { - public OsuBeatmapConverter(IBeatmap beatmap) - : base(beatmap) + public OsuBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) + : base(beatmap, ruleset) { } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index cab1980dde..57d99df5fb 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new OsuScoreProcessor(beatmap); - public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap, this); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap); diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 10cc861b7e..96e7722e73 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -41,10 +41,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(HitObject) }; - public TaikoBeatmapConverter(IBeatmap beatmap) - : base(beatmap) + public TaikoBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) + : base(beatmap, ruleset) { - isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(new TaikoRuleset().RulesetInfo); + isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); } protected override Beatmap ConvertBeatmap(IBeatmap original) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index a4cfce0dcc..529dfe765c 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new TaikoScoreProcessor(beatmap); - public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this); public const string SHORT_NAME = "taiko"; diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 26e70f19e4..33f484a9aa 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; using osu.Game.IO; +using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; @@ -313,7 +314,7 @@ namespace osu.Game.Tests.Beatmaps.Formats { var beatmap = decoder.Decode(stream); - var converted = new OsuBeatmapConverter(beatmap).Convert(); + var converted = new OsuBeatmapConverter(beatmap, new OsuRuleset()).Convert(); new OsuBeatmapProcessor(converted).PreProcess(); new OsuBeatmapProcessor(converted).PostProcess(); @@ -336,7 +337,7 @@ namespace osu.Game.Tests.Beatmaps.Formats { var beatmap = decoder.Decode(stream); - var converted = new CatchBeatmapConverter(beatmap).Convert(); + var converted = new CatchBeatmapConverter(beatmap, new CatchRuleset()).Convert(); new CatchBeatmapProcessor(converted).PreProcess(); new CatchBeatmapProcessor(converted).PostProcess(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index ae20bbc86d..dc950e43bd 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -198,7 +198,7 @@ namespace osu.Game.Tests.Visual.Gameplay public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new TestDrawableScrollingRuleset(this, beatmap, mods); - public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TestBeatmapConverter(beatmap, null); public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException(); @@ -268,8 +268,8 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestBeatmapConverter : BeatmapConverter { - public TestBeatmapConverter(IBeatmap beatmap) - : base(beatmap) + public TestBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) + : base(beatmap, ruleset) { } diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index 7922843626..e6de1eebcd 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; namespace osu.Game.Beatmaps @@ -25,7 +26,7 @@ namespace osu.Game.Beatmaps public IBeatmap Beatmap { get; } - protected BeatmapConverter(IBeatmap beatmap) + protected BeatmapConverter(IBeatmap beatmap, Ruleset ruleset) { Beatmap = beatmap; } From d87203857b24c55b1bc8fb58229d9743c142044d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Dec 2019 16:02:35 +0900 Subject: [PATCH 63/86] Move default construction into constructor --- osu.Game/Rulesets/Ruleset.cs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 21d96123f1..107633194f 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -51,7 +51,14 @@ namespace osu.Game.Rulesets protected Ruleset() { - RulesetInfo = createRulesetInfo(); + RulesetInfo = new RulesetInfo + { + Name = Description, + ShortName = ShortName, + ID = (this as ILegacyRuleset)?.LegacyID, + InstantiationInfo = GetType().AssemblyQualifiedName, + Available = true + }; } /// @@ -133,17 +140,5 @@ namespace osu.Game.Rulesets /// /// An empty frame for the current ruleset, or null if unsupported. public virtual IConvertibleReplayFrame CreateConvertibleReplayFrame() => null; - - /// - /// Create a ruleset info based on this ruleset. - /// - /// A filled . - private RulesetInfo createRulesetInfo() => new RulesetInfo - { - Name = Description, - ShortName = ShortName, - InstantiationInfo = GetType().AssemblyQualifiedName, - Available = true - }; } } From 57382676422d614f87cb3e7177234b8a2068028e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Dec 2019 16:05:20 +0900 Subject: [PATCH 64/86] Copy ruleset info over default --- osu.Game/Rulesets/RulesetInfo.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RulesetInfo.cs b/osu.Game/Rulesets/RulesetInfo.cs index d695e0b56d..ececc18c96 100644 --- a/osu.Game/Rulesets/RulesetInfo.cs +++ b/osu.Game/Rulesets/RulesetInfo.cs @@ -20,11 +20,17 @@ namespace osu.Game.Rulesets [JsonIgnore] public bool Available { get; set; } + // TODO: this should probably be moved to RulesetStore. public virtual Ruleset CreateInstance() { if (!Available) return null; - return (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo)); + var ruleset = (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo)); + + // overwrite the pre-populated RulesetInfo with a potentially database attached copy. + ruleset.RulesetInfo = this; + + return ruleset; } public bool Equals(RulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo; From fcb7a9ade50320e552236810c4ad5aff7b5d0e58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Dec 2019 16:16:55 +0900 Subject: [PATCH 65/86] Update RulesetStore to read from populated defaults --- osu.Game/Rulesets/RulesetStore.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5d2a7df458..a389d4ff75 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -58,16 +58,11 @@ namespace osu.Game.Rulesets var instances = loadedAssemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r)).ToList(); - //add all legacy modes in correct order + //add all legacy rulesets first to ensure they have exclusive choice of primary key. foreach (var r in instances.Where(r => r is ILegacyRuleset)) { - int legacyId = ((ILegacyRuleset)r).LegacyID; - - if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == legacyId) == null) - { - r.RulesetInfo.ID = legacyId; + if (context.RulesetInfo.SingleOrDefault(dbRuleset => dbRuleset.ID == r.RulesetInfo.ID) == null) context.RulesetInfo.Add(r.RulesetInfo); - } } context.SaveChanges(); From 00546787c889489362283dc28d998c2f035c8d3a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Dec 2019 20:36:57 +0900 Subject: [PATCH 66/86] Remove unused method --- osu.Game/Rulesets/Scoring/HealthProcessor.cs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs index 8af8177083..d05e2d7b6b 100644 --- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs @@ -80,23 +80,5 @@ namespace osu.Game.Rulesets.Scoring Health.Value = 1; HasFailed = false; } - - /// - /// Checks if the score is in a failed state and notifies subscribers. - /// - /// This can only ever notify subscribers once. - /// - /// - private void updateFailed(JudgementResult result) - { - if (HasFailed) - return; - - if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true) - return; - - if (Failed?.Invoke() != false) - HasFailed = true; - } } } From e088a856620a584ba4dd8b639e9033b6df7f65f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Dec 2019 17:12:12 +0900 Subject: [PATCH 67/86] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index dd11804b90..d684b73d8d 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -54,6 +54,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 757e0e11fa..4c5f3e0f38 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 0dba92b975..ccfbee9a62 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -74,7 +74,7 @@ - + @@ -82,7 +82,7 @@ - + From e3753ae29fb88c1aec22896abf4bdcd54df6ded6 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 23 Dec 2019 11:23:03 +0100 Subject: [PATCH 68/86] Make the easy mod's extra life count customizable --- osu.Game/Rulesets/Mods/ModEasy.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModEasy.cs b/osu.Game/Rulesets/Mods/ModEasy.cs index a55ebc51d6..7f52cccbc5 100644 --- a/osu.Game/Rulesets/Mods/ModEasy.cs +++ b/osu.Game/Rulesets/Mods/ModEasy.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; @@ -21,7 +22,14 @@ namespace osu.Game.Rulesets.Mods public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) }; - private int retries = 2; + [SettingSource("Extra Lives", "Number of extra lives")] + public Bindable Retries { get; } = new BindableInt(2) + { + MinValue = 0, + MaxValue = 10 + }; + + private int retries; private BindableNumber health; @@ -32,6 +40,8 @@ namespace osu.Game.Rulesets.Mods difficulty.ApproachRate *= ratio; difficulty.DrainRate *= ratio; difficulty.OverallDifficulty *= ratio; + + retries = Retries.Value; } public bool AllowFail From bc75bd34f6222c5fa3ccd5678d745700061e10a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Dec 2019 18:23:09 +0900 Subject: [PATCH 69/86] Fix caret width having changed --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 72fa135699..f5b7bc3073 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -16,6 +16,8 @@ namespace osu.Game.Graphics.UserInterface { protected override float LeftRightPadding => 10; + protected override float CaretWidth => 3; + protected override SpriteText CreatePlaceholder() => new OsuSpriteText { Font = OsuFont.GetFont(italics: true), From 36dd0e69980eb39c4df566a4ead1b5773dec737d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Dec 2019 11:14:40 +0900 Subject: [PATCH 70/86] Make ellipsis length into a static --- osu.Desktop/DiscordRichPresence.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index ce878edda8..73c717b97c 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -98,17 +98,17 @@ namespace osu.Desktop client.SetPresence(presence); } + private static readonly int ellipsis_length = Encoding.UTF8.GetByteCount(new[] { '…' }); + private string truncate(ReadOnlySpan str) { if (Encoding.UTF8.GetByteCount(str) <= 128) return new string(str); - int ellipsisLength = Encoding.UTF8.GetByteCount(new[] { '…' }); - do { str = str[..^1]; - } while (Encoding.UTF8.GetByteCount(str) + ellipsisLength > 128); + } while (Encoding.UTF8.GetByteCount(str) + ellipsis_length > 128); return new string(str) + '…'; } From 1a7937bcf73f0fe3bc87666df542b6e1c0cd3ba6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 25 Dec 2019 12:04:28 +0900 Subject: [PATCH 71/86] Apply suggested optimisations --- osu.Desktop/DiscordRichPresence.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 73c717b97c..05004cf76e 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -100,17 +100,23 @@ namespace osu.Desktop private static readonly int ellipsis_length = Encoding.UTF8.GetByteCount(new[] { '…' }); - private string truncate(ReadOnlySpan str) + private string truncate(string str) { if (Encoding.UTF8.GetByteCount(str) <= 128) - return new string(str); + return str; + + ReadOnlyMemory strMem = str.AsMemory(); do { - str = str[..^1]; - } while (Encoding.UTF8.GetByteCount(str) + ellipsis_length > 128); + strMem = strMem[..^1]; + } while (Encoding.UTF8.GetByteCount(strMem.Span) + ellipsis_length > 128); - return new string(str) + '…'; + return string.Create(strMem.Length + 1, strMem, (span, mem) => + { + mem.Span.CopyTo(span); + span[^1] = '…'; + }); } private string getDetails(UserActivity activity) From 145ac8e0b547c3f8472f4a0344dec7b6e3a4730a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 14:55:05 +0900 Subject: [PATCH 72/86] Remove redundant setter --- osu.Game/Beatmaps/Formats/IHasComboColours.cs | 2 +- osu.Game/Skinning/SkinConfiguration.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/IHasComboColours.cs b/osu.Game/Beatmaps/Formats/IHasComboColours.cs index ac0d32dbaa..41c85db063 100644 --- a/osu.Game/Beatmaps/Formats/IHasComboColours.cs +++ b/osu.Game/Beatmaps/Formats/IHasComboColours.cs @@ -11,7 +11,7 @@ namespace osu.Game.Beatmaps.Formats /// /// Retrieves the list of combo colours for presentation only. /// - IReadOnlyList ComboColours { get; set; } + IReadOnlyList ComboColours { get; } /// /// Adds combo colours to the list. diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index e3a0ab23fa..a55870aa6d 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; using osu.Game.Beatmaps.Formats; using osuTK.Graphics; @@ -28,7 +27,7 @@ namespace osu.Game.Skinning new Color4(242, 24, 57, 255), }; - private List comboColours = new List(); + private readonly List comboColours = new List(); public IReadOnlyList ComboColours { @@ -42,7 +41,6 @@ namespace osu.Game.Skinning return null; } - set => comboColours = value.ToList(); } public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours); From 04cbdd9c6c253f04a63b13fd9052cbe1cf181477 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 14:55:13 +0900 Subject: [PATCH 73/86] Make test easier to visually examine --- osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index c26afefc41..9adcf26529 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Tests { public static Color4[] Colours { get; } = { - new Color4(10, 100, 150, 255), + new Color4(150, 100, 50, 255), new Color4(20, 20, 20, 255), }; From 783159f7a06de9438552f0de2b9654662b78b6ac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 14:55:22 +0900 Subject: [PATCH 74/86] Remove redundant logic --- osu.Game/Skinning/DefaultSkinConfiguration.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Skinning/DefaultSkinConfiguration.cs b/osu.Game/Skinning/DefaultSkinConfiguration.cs index 8e89ab25b2..5842ee82ee 100644 --- a/osu.Game/Skinning/DefaultSkinConfiguration.cs +++ b/osu.Game/Skinning/DefaultSkinConfiguration.cs @@ -8,9 +8,5 @@ namespace osu.Game.Skinning /// public class DefaultSkinConfiguration : SkinConfiguration { - public DefaultSkinConfiguration() - { - ComboColours = DefaultComboColours; - } } } From 9090d13e05ffe278e31c951f7f8ebf9d990da11c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 15:01:05 +0900 Subject: [PATCH 75/86] Simplify tests --- .../TestSceneLegacyBeatmapSkin.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index 9adcf26529..e26b671d57 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -9,8 +9,8 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.IO.Stores; +using osu.Framework.Testing; using osu.Game.Beatmaps; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens; using osu.Game.Screens.Play; @@ -30,39 +30,33 @@ namespace osu.Game.Rulesets.Osu.Tests public void TestBeatmapComboColours() { ExposedPlayer player = null; - IReadOnlyList colours = null; - AddStep("load beatmap", () => player = loadBeatmap(false, true)); + AddStep("load coloured beatmap", () => player = loadBeatmap(false, true)); AddUntilStep("wait for player", () => player.IsLoaded); - AddStep("retrieve combo colours", () => colours = player.BeatmapSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); - AddAssert("is beatmap skin colours", () => colours.SequenceEqual(TestBeatmapSkin.Colours)); + AddAssert("is beatmap skin colours", () => player.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); } [Test] public void TestEmptyBeatmapComboColours() { ExposedPlayer player = null; - IReadOnlyList colours = null; AddStep("load no-colour beatmap", () => player = loadBeatmap(false, false)); AddUntilStep("wait for player", () => player.IsLoaded); - AddStep("retrieve combo colours", () => colours = player.BeatmapSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); - AddAssert("is default user skin colours", () => colours.SequenceEqual(SkinConfiguration.DefaultComboColours)); + AddAssert("is default user skin colours", () => player.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours)); } [Test] public void TestEmptyBeatmapCustomSkinColours() { ExposedPlayer player = null; - IReadOnlyList colours = null; - AddStep("load no-colour beatmap", () => player = loadBeatmap(true, false)); + AddStep("load custom-skin colour", () => player = loadBeatmap(true, false)); AddUntilStep("wait for player", () => player.IsLoaded); - AddStep("retrieve combo colours", () => colours = player.BeatmapSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value); - AddAssert("is custom user skin colours", () => colours.SequenceEqual(TestSkin.Colours)); + AddAssert("is custom user skin colours", () => player.UsableComboColours.SequenceEqual(TestSkin.Colours)); } private ExposedPlayer loadBeatmap(bool userHasCustomColours, bool beatmapHasColours) @@ -92,7 +86,10 @@ namespace osu.Game.Rulesets.Osu.Tests return dependencies; } - public BeatmapSkinProvidingContainer BeatmapSkin => GameplayClockContainer.OfType().First().OfType().First(); + public IReadOnlyList UsableComboColours => + GameplayClockContainer.ChildrenOfType() + .First() + .GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value; } private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap From 3485ef33a726b1caee8a0245188691d79da38674 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 15:05:08 +0900 Subject: [PATCH 76/86] Rename tests and add missing coverage --- .../TestSceneLegacyBeatmapSkin.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index e26b671d57..4676f14655 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -26,19 +26,20 @@ namespace osu.Game.Rulesets.Osu.Tests [Resolved] private AudioManager audio { get; set; } - [Test] - public void TestBeatmapComboColours() + [TestCase(true)] + [TestCase(false)] + public void TestBeatmapComboColours(bool customSkinColoursPresent) { ExposedPlayer player = null; - AddStep("load coloured beatmap", () => player = loadBeatmap(false, true)); + AddStep("load coloured beatmap", () => player = loadBeatmap(customSkinColoursPresent, true)); AddUntilStep("wait for player", () => player.IsLoaded); AddAssert("is beatmap skin colours", () => player.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours)); } [Test] - public void TestEmptyBeatmapComboColours() + public void TestBeatmapNoComboColours() { ExposedPlayer player = null; @@ -49,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Tests } [Test] - public void TestEmptyBeatmapCustomSkinColours() + public void TestBeatmapNoComboColoursSkinOverride() { ExposedPlayer player = null; From 52ba0cd816381fe5a1208c7aba8266caa0f839b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 15:20:04 +0900 Subject: [PATCH 77/86] Rename method to be more appropriate Also adds xmldoc. --- .../Mods/CatchModDifficultyAdjust.cs | 4 ++-- osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs | 4 ++-- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 12 ++++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs index 2e1e655844..a3e314eee8 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs @@ -30,9 +30,9 @@ namespace osu.Game.Rulesets.Catch.Mods Value = 5, }; - protected override void UpdateSettings(BeatmapDifficulty difficulty) + protected override void TransferSettings(BeatmapDifficulty difficulty) { - base.UpdateSettings(difficulty); + base.TransferSettings(difficulty); CircleSize.Value = CircleSize.Default = difficulty.CircleSize; ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index 3e9c51db85..6c76de5440 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -30,9 +30,9 @@ namespace osu.Game.Rulesets.Osu.Mods Value = 5, }; - protected override void UpdateSettings(BeatmapDifficulty difficulty) + protected override void TransferSettings(BeatmapDifficulty difficulty) { - base.UpdateSettings(difficulty); + base.TransferSettings(difficulty); CircleSize.Value = CircleSize.Default = difficulty.CircleSize; ApproachRate.Value = ApproachRate.Default = difficulty.ApproachRate; diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 1405ccec8d..9721784aee 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -52,18 +52,26 @@ namespace osu.Game.Rulesets.Mods if (this.difficulty == null || this.difficulty.ID != difficulty.ID) { this.difficulty = difficulty; - UpdateSettings(difficulty); + TransferSettings(difficulty); } else ApplySettings(difficulty); } - protected virtual void UpdateSettings(BeatmapDifficulty difficulty) + /// + /// Transfer initial settings from the beatmap to settings. + /// + /// The beatmap's initial values. + protected virtual void TransferSettings(BeatmapDifficulty difficulty) { DrainRate.Value = DrainRate.Default = difficulty.DrainRate; OverallDifficulty.Value = OverallDifficulty.Default = difficulty.OverallDifficulty; } + /// + /// Apply all custom settings to the provided beatmap. + /// + /// The beatmap to have settings applied. protected virtual void ApplySettings(BeatmapDifficulty difficulty) { difficulty.DrainRate = DrainRate.Value; From 911dc2d98dfe1074feeba9d9b83dd2ebaa9a02ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 15:20:10 +0900 Subject: [PATCH 78/86] Fix code inspections --- osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs | 4 ++-- osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs | 4 ++-- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs index a3e314eee8..4c0f5d510e 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Catch.Mods public class CatchModDifficultyAdjust : ModDifficultyAdjust { [SettingSource("Fruit Size", "Override a beatmap's set CS.")] - public BindableNumber CircleSize { get; } = new BindableFloat() + public BindableNumber CircleSize { get; } = new BindableFloat { Precision = 0.1f, MinValue = 1, @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.Mods }; [SettingSource("Approach Rate", "Override a beatmap's set AR.")] - public BindableNumber ApproachRate { get; } = new BindableFloat() + public BindableNumber ApproachRate { get; } = new BindableFloat { Precision = 0.1f, MinValue = 1, diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index 6c76de5440..0514e2ab34 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Mods public class OsuModDifficultyAdjust : ModDifficultyAdjust { [SettingSource("Circle Size", "Override a beatmap's set CS.")] - public BindableNumber CircleSize { get; } = new BindableFloat() + public BindableNumber CircleSize { get; } = new BindableFloat { Precision = 0.1f, MinValue = 1, @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods }; [SettingSource("Approach Rate", "Override a beatmap's set AR.")] - public BindableNumber ApproachRate { get; } = new BindableFloat() + public BindableNumber ApproachRate { get; } = new BindableFloat { Precision = 0.1f, MinValue = 1, diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 9721784aee..224fc78508 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModHardRock) }; [SettingSource("Drain Rate", "Override a beatmap's set HP.")] - public BindableNumber DrainRate { get; } = new BindableFloat() + public BindableNumber DrainRate { get; } = new BindableFloat { Precision = 0.1f, MinValue = 1, @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mods }; [SettingSource("Overall Difficulty", "Override a beatmap's set OD.")] - public BindableNumber OverallDifficulty { get; } = new BindableFloat() + public BindableNumber OverallDifficulty { get; } = new BindableFloat { Precision = 0.1f, MinValue = 1, From 81c330ec2677d07e091e31254bfc665bed282d85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Dec 2019 18:51:44 +0900 Subject: [PATCH 79/86] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index d684b73d8d..e7f90af5fd 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -54,6 +54,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4c5f3e0f38..0c0a58d533 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ccfbee9a62..edeeea239e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -74,7 +74,7 @@ - + @@ -82,7 +82,7 @@ - + From a47e5aeead8382a9b889d30c3e16183bf6a7ae7f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Dec 2019 00:51:44 +0900 Subject: [PATCH 80/86] Fix sample lookup not working correctly for custom rulesets --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index df1b8078a6..f318539bb7 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -159,7 +159,7 @@ namespace osu.Game.Rulesets.UI dependencies.Cache(textureStore); localSampleStore = dependencies.Get().GetSampleStore(new NamespacedResourceStore(resources, "Samples")); - dependencies.CacheAs(new FallbackSampleStore(localSampleStore, dependencies.Get())); + dependencies.CacheAs(new FallbackSampleStore(localSampleStore, dependencies.Get())); } onScreenDisplay = dependencies.Get(); From 96a4f9ae53f537c236a17ad4728bf92c0ad87831 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Dec 2019 15:14:19 +0900 Subject: [PATCH 81/86] Fix nub position getting offset by size changes --- .../Graphics/UserInterface/OsuSliderBar.cs | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 563dc2dad9..958390d5d2 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; @@ -31,6 +32,7 @@ namespace osu.Game.Graphics.UserInterface protected readonly Nub Nub; private readonly Box leftBox; private readonly Box rightBox; + private readonly Container nubContainer; public virtual string TooltipText { get; private set; } @@ -72,10 +74,15 @@ namespace osu.Game.Graphics.UserInterface Origin = Anchor.CentreRight, Alpha = 0.5f, }, - Nub = new Nub + nubContainer = new Container { - Origin = Anchor.TopCentre, - Expanded = true, + RelativeSizeAxes = Axes.Both, + Child = Nub = new Nub + { + Origin = Anchor.TopCentre, + RelativePositionAxes = Axes.X, + Expanded = true, + }, }, new HoverClickSounds() }; @@ -90,6 +97,13 @@ namespace osu.Game.Graphics.UserInterface AccentColour = colours.Pink; } + protected override void Update() + { + base.Update(); + + nubContainer.Padding = new MarginPadding { Horizontal = RangePadding }; + } + protected override void LoadComplete() { base.LoadComplete(); @@ -176,14 +190,14 @@ namespace osu.Game.Graphics.UserInterface { base.UpdateAfterChildren(); leftBox.Scale = new Vector2(Math.Clamp( - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1); + RangePadding + Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1); rightBox.Scale = new Vector2(Math.Clamp( - DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1); + DrawWidth - Nub.DrawPosition.X - RangePadding - Nub.DrawWidth / 2, 0, DrawWidth), 1); } protected override void UpdateValue(float value) { - Nub.MoveToX(RangePadding + UsableWidth * value, 250, Easing.OutQuint); + Nub.MoveToX(value, 250, Easing.OutQuint); } /// From 9a013acb26b84e162e0a9a53d748728d93de7646 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Thu, 26 Dec 2019 14:25:41 +0800 Subject: [PATCH 82/86] Fix name typo of OsuModObjectScaleTween --- osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 2 +- .../{OsuModeObjectScaleTween.cs => OsuModObjectScaleTween.cs} | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename osu.Game.Rulesets.Osu/Mods/{OsuModeObjectScaleTween.cs => OsuModObjectScaleTween.cs} (96%) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs index adca95cf8a..9bf7525d33 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModDeflate : OsuModeObjectScaleTween + public class OsuModDeflate : OsuModObjectScaleTween { public override string Name => "Deflate"; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index 3c81203ad7..76676ce888 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Rulesets.Osu.Mods { - internal class OsuModGrow : OsuModeObjectScaleTween + internal class OsuModGrow : OsuModObjectScaleTween { public override string Name => "Grow"; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs rename to osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs index 923278f484..42ddddc4dd 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Mods /// /// Adjusts the size of hit objects during their fade in animation. /// - public abstract class OsuModeObjectScaleTween : Mod, IReadFromConfig, IApplicableToDrawableHitObjects + public abstract class OsuModObjectScaleTween : Mod, IReadFromConfig, IApplicableToDrawableHitObjects { public override ModType Type => ModType.Fun; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs index e786ec86f9..eae218509e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; // todo: this mod should be able to be compatible with hidden with a bit of further implementation. - public override Type[] IncompatibleMods => new[] { typeof(OsuModeObjectScaleTween), typeof(OsuModHidden), typeof(OsuModTraceable) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModObjectScaleTween), typeof(OsuModHidden), typeof(OsuModTraceable) }; private const int rotate_offset = 360; private const float rotate_starting_width = 2; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index cf1ce517e8..dff9a77807 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModSpinIn), typeof(OsuModeObjectScaleTween) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModSpinIn), typeof(OsuModObjectScaleTween) }; private Bindable increaseFirstObjectVisibility = new Bindable(); public void ReadFromConfig(OsuConfigManager config) From d45556eb6a07280a6be18c275fa5e3b9aa340e09 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Dec 2019 17:57:16 +0900 Subject: [PATCH 83/86] Remove whitespace --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 1 - osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 5bca8588b6..a579a7d07e 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -41,7 +41,6 @@ namespace osu.Game.Rulesets.Mania public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this); - public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score); public const string SHORT_NAME = "mania"; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index c5c2027af1..d713a4145d 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -34,7 +34,6 @@ namespace osu.Game.Rulesets.Taiko public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this); - public const string SHORT_NAME = "taiko"; public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] From 8903f286efa4e92c6276fc18ea29af29d0b5f8d2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Dec 2019 18:27:48 +0900 Subject: [PATCH 84/86] Fix escape not continuing to results screen --- osu.Game/Screens/Play/Player.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 8970f9ac88..ab32c55229 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -541,8 +541,14 @@ namespace osu.Game.Screens.Play { if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed) { - // proceed to result screen if beatmap already finished playing - completionProgressDelegate.RunTask(); + // Proceed to result screen if beatmap already finished playing. + // This is scheduled since the player needs to become the current screen before the delegate runs. This happens after the return true. + Scheduler.Add(() => + { + if (!completionProgressDelegate.Completed && !completionProgressDelegate.Cancelled) + completionProgressDelegate.RunTask(); + }); + return true; } From a041f32072ac44dd1d0ae9c6877ce7e753fc161e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Dec 2019 19:05:32 +0900 Subject: [PATCH 85/86] Use cleaner solution via cancellation of older schedule --- osu.Game/Screens/Play/Player.cs | 36 +++++++++++++++------------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ab32c55229..6368c30def 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -350,18 +350,7 @@ namespace osu.Game.Screens.Play if (!showResults) return; using (BeginDelayedSequence(1000)) - { - completionProgressDelegate = Schedule(delegate - { - if (!this.IsCurrentScreen()) return; - - var score = CreateScore(); - if (DrawableRuleset.ReplayScore == null) - scoreManager.Import(score).Wait(); - - this.Push(CreateResults(score)); - }); - } + scheduleGotoRanking(); } protected virtual ScoreInfo CreateScore() @@ -541,14 +530,8 @@ namespace osu.Game.Screens.Play { if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed) { - // Proceed to result screen if beatmap already finished playing. - // This is scheduled since the player needs to become the current screen before the delegate runs. This happens after the return true. - Scheduler.Add(() => - { - if (!completionProgressDelegate.Completed && !completionProgressDelegate.Cancelled) - completionProgressDelegate.RunTask(); - }); - + // proceed to result screen if beatmap already finished playing + scheduleGotoRanking(); return true; } @@ -583,6 +566,19 @@ namespace osu.Game.Screens.Play storyboardReplacesBackground.Value = false; } + private void scheduleGotoRanking() + { + completionProgressDelegate?.Cancel(); + completionProgressDelegate = Schedule(delegate + { + var score = CreateScore(); + if (DrawableRuleset.ReplayScore == null) + scoreManager.Import(score).Wait(); + + this.Push(CreateResults(score)); + }); + } + #endregion } } From 00a36c388c76db43e9373369c1c54c9cf8a0c905 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 26 Dec 2019 19:18:39 +0900 Subject: [PATCH 86/86] Fix tests --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 ++ osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index c8a156dc57..c9ea5e6cf1 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -38,6 +38,8 @@ namespace osu.Game.Rulesets.Osu public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new OsuScoreProcessor(beatmap); + public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new OsuHealthProcessor(beatmap); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap, this); public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs index a0c25521a6..2045072c79 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs @@ -22,12 +22,12 @@ namespace osu.Game.Tests.Visual.Gameplay { AddUntilStep("wait for fail", () => Player.HasFailed); AddUntilStep("wait for multiple judged objects", () => ((FailPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.Count(h => h.AllJudged) > 1); - AddAssert("total judgements == 1", () => ((FailPlayer)Player).ScoreProcessor.JudgedHits == 1); + AddAssert("total judgements == 1", () => ((FailPlayer)Player).HealthProcessor.JudgedHits >= 1); } private class FailPlayer : TestPlayer { - public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + public new HealthProcessor HealthProcessor => base.HealthProcessor; public FailPlayer() : base(false, false)